Passed
Push — master ( e2c5b5...98e0e0 )
by Julito
10:18
created

DocumentManager::unsetDocumentAsTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 16
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 26
rs 9.7333
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
6
/**
7
 *  Class DocumentManager
8
 *  This is the document library for Chamilo.
9
 *  It is / will be used to provide a service layer to all document-using tools.
10
 *  and eliminate code duplication fro group documents, scorm documents, main documents.
11
 *  Include/require it in your code to use its functionality.
12
 *
13
 * @package chamilo.library
14
 */
15
class DocumentManager
16
{
17
    /**
18
     * Construct.
19
     */
20
    private function __construct()
21
    {
22
    }
23
24
    /**
25
     * @param string $course_code
26
     *
27
     * @return int the document folder quota for the current course in bytes
28
     *             or the default quota
29
     */
30
    public static function get_course_quota($course_code = null)
31
    {
32
        if (empty($course_code)) {
33
            $course_info = api_get_course_info();
34
        } else {
35
            $course_info = api_get_course_info($course_code);
36
        }
37
38
        $course_quota = null;
39
        if (empty($course_info)) {
40
            return DEFAULT_DOCUMENT_QUOTA;
41
        } else {
42
            $course_quota = $course_info['disk_quota'];
43
        }
44
        if (is_null($course_quota) || empty($course_quota)) {
45
            // Course table entry for quota was null, then use default value
46
            $course_quota = DEFAULT_DOCUMENT_QUOTA;
47
        }
48
49
        return $course_quota;
50
    }
51
52
    /**
53
     * Get the content type of a file by checking the extension
54
     * We could use mime_content_type() with php-versions > 4.3,
55
     * but this doesn't work as it should on Windows installations.
56
     *
57
     * @param string $filename or boolean TRUE to return complete array
58
     *
59
     * @author ? first version
60
     * @author Bert Vanderkimpen
61
     *
62
     * @return string
63
     */
64
    public static function file_get_mime_type($filename)
65
    {
66
        // All MIME types in an array (from 1.6, this is the authorative source)
67
        // Please, keep this alphabetical if you add something to this list!
68
        $mime_types = [
69
            'ai' => 'application/postscript',
70
            'aif' => 'audio/x-aiff',
71
            'aifc' => 'audio/x-aiff',
72
            'aiff' => 'audio/x-aiff',
73
            'asf' => 'video/x-ms-asf',
74
            'asc' => 'text/plain',
75
            'au' => 'audio/basic',
76
            'avi' => 'video/x-msvideo',
77
            'bcpio' => 'application/x-bcpio',
78
            'bin' => 'application/octet-stream',
79
            'bmp' => 'image/bmp',
80
            'cdf' => 'application/x-netcdf',
81
            'class' => 'application/octet-stream',
82
            'cpio' => 'application/x-cpio',
83
            'cpt' => 'application/mac-compactpro',
84
            'csh' => 'application/x-csh',
85
            'css' => 'text/css',
86
            'dcr' => 'application/x-director',
87
            'dir' => 'application/x-director',
88
            'djv' => 'image/vnd.djvu',
89
            'djvu' => 'image/vnd.djvu',
90
            'dll' => 'application/octet-stream',
91
            'dmg' => 'application/x-diskcopy',
92
            'dms' => 'application/octet-stream',
93
            'doc' => 'application/msword',
94
            'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
95
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
96
            'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
97
            'dvi' => 'application/x-dvi',
98
            'dwg' => 'application/vnd.dwg',
99
            'dwf' => 'application/vnd.dwf',
100
            'dxf' => 'application/vnd.dxf',
101
            'dxr' => 'application/x-director',
102
            'eps' => 'application/postscript',
103
            'epub' => 'application/epub+zip',
104
            'etx' => 'text/x-setext',
105
            'exe' => 'application/octet-stream',
106
            'ez' => 'application/andrew-inset',
107
            'flv' => 'video/flv',
108
            'gif' => 'image/gif',
109
            'gtar' => 'application/x-gtar',
110
            'gz' => 'application/x-gzip',
111
            'hdf' => 'application/x-hdf',
112
            'hqx' => 'application/mac-binhex40',
113
            'htm' => 'text/html',
114
            'html' => 'text/html',
115
            'ice' => 'x-conference-xcooltalk',
116
            'ief' => 'image/ief',
117
            'iges' => 'model/iges',
118
            'igs' => 'model/iges',
119
            'jar' => 'application/java-archiver',
120
            'jpe' => 'image/jpeg',
121
            'jpeg' => 'image/jpeg',
122
            'jpg' => 'image/jpeg',
123
            'js' => 'application/x-javascript',
124
            'kar' => 'audio/midi',
125
            'lam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
126
            'latex' => 'application/x-latex',
127
            'lha' => 'application/octet-stream',
128
            'log' => 'text/plain',
129
            'lzh' => 'application/octet-stream',
130
            'm1a' => 'audio/mpeg',
131
            'm2a' => 'audio/mpeg',
132
            'm3u' => 'audio/x-mpegurl',
133
            'man' => 'application/x-troff-man',
134
            'me' => 'application/x-troff-me',
135
            'mesh' => 'model/mesh',
136
            'mid' => 'audio/midi',
137
            'midi' => 'audio/midi',
138
            'mov' => 'video/quicktime',
139
            'movie' => 'video/x-sgi-movie',
140
            'mp2' => 'audio/mpeg',
141
            'mp3' => 'audio/mpeg',
142
            'mp4' => 'video/mp4',
143
            'mpa' => 'audio/mpeg',
144
            'mpe' => 'video/mpeg',
145
            'mpeg' => 'video/mpeg',
146
            'mpg' => 'video/mpeg',
147
            'mpga' => 'audio/mpeg',
148
            'ms' => 'application/x-troff-ms',
149
            'msh' => 'model/mesh',
150
            'mxu' => 'video/vnd.mpegurl',
151
            'nc' => 'application/x-netcdf',
152
            'oda' => 'application/oda',
153
            'oga' => 'audio/ogg',
154
            'ogg' => 'application/ogg',
155
            'ogx' => 'application/ogg',
156
            'ogv' => 'video/ogg',
157
            'pbm' => 'image/x-portable-bitmap',
158
            'pct' => 'image/pict',
159
            'pdb' => 'chemical/x-pdb',
160
            'pdf' => 'application/pdf',
161
            'pgm' => 'image/x-portable-graymap',
162
            'pgn' => 'application/x-chess-pgn',
163
            'pict' => 'image/pict',
164
            'png' => 'image/png',
165
            'pnm' => 'image/x-portable-anymap',
166
            'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
167
            'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
168
            'pps' => 'application/vnd.ms-powerpoint',
169
            'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
170
            'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
171
            'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
172
            'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
173
            'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
174
            'ppm' => 'image/x-portable-pixmap',
175
            'ppt' => 'application/vnd.ms-powerpoint',
176
            'pps' => 'application/vnd.ms-powerpoint',
177
            'ps' => 'application/postscript',
178
            'qt' => 'video/quicktime',
179
            'ra' => 'audio/x-realaudio',
180
            'ram' => 'audio/x-pn-realaudio',
181
            'rar' => 'image/x-rar-compressed',
182
            'ras' => 'image/x-cmu-raster',
183
            'rgb' => 'image/x-rgb',
184
            'rm' => 'audio/x-pn-realaudio',
185
            'roff' => 'application/x-troff',
186
            'rpm' => 'audio/x-pn-realaudio-plugin',
187
            'rtf' => 'text/rtf',
188
            'rtx' => 'text/richtext',
189
            'sgm' => 'text/sgml',
190
            'sgml' => 'text/sgml',
191
            'sh' => 'application/x-sh',
192
            'shar' => 'application/x-shar',
193
            'silo' => 'model/mesh',
194
            'sib' => 'application/X-Sibelius-Score',
195
            'sit' => 'application/x-stuffit',
196
            'skd' => 'application/x-koan',
197
            'skm' => 'application/x-koan',
198
            'skp' => 'application/x-koan',
199
            'skt' => 'application/x-koan',
200
            'smi' => 'application/smil',
201
            'smil' => 'application/smil',
202
            'snd' => 'audio/basic',
203
            'so' => 'application/octet-stream',
204
            'spl' => 'application/x-futuresplash',
205
            'src' => 'application/x-wais-source',
206
            'sv4cpio' => 'application/x-sv4cpio',
207
            'sv4crc' => 'application/x-sv4crc',
208
            'svf' => 'application/vnd.svf',
209
            'svg' => 'image/svg+xml',
210
            //'svgz' => 'image/svg+xml',
211
            'swf' => 'application/x-shockwave-flash',
212
            'sxc' => 'application/vnd.sun.xml.calc',
213
            'sxi' => 'application/vnd.sun.xml.impress',
214
            'sxw' => 'application/vnd.sun.xml.writer',
215
            't' => 'application/x-troff',
216
            'tar' => 'application/x-tar',
217
            'tcl' => 'application/x-tcl',
218
            'tex' => 'application/x-tex',
219
            'texi' => 'application/x-texinfo',
220
            'texinfo' => 'application/x-texinfo',
221
            'tga' => 'image/x-targa',
222
            'tif' => 'image/tif',
223
            'tiff' => 'image/tiff',
224
            'tr' => 'application/x-troff',
225
            'tsv' => 'text/tab-seperated-values',
226
            'txt' => 'text/plain',
227
            'ustar' => 'application/x-ustar',
228
            'vcd' => 'application/x-cdlink',
229
            'vrml' => 'model/vrml',
230
            'wav' => 'audio/x-wav',
231
            'wbmp' => 'image/vnd.wap.wbmp',
232
            'wbxml' => 'application/vnd.wap.wbxml',
233
            'wml' => 'text/vnd.wap.wml',
234
            'wmlc' => 'application/vnd.wap.wmlc',
235
            'wmls' => 'text/vnd.wap.wmlscript',
236
            'wmlsc' => 'application/vnd.wap.wmlscriptc',
237
            'wma' => 'audio/x-ms-wma',
238
            'wmv' => 'video/x-ms-wmv',
239
            'wrl' => 'model/vrml',
240
            'xbm' => 'image/x-xbitmap',
241
            'xht' => 'application/xhtml+xml',
242
            'xhtml' => 'application/xhtml+xml',
243
            'xls' => 'application/vnd.ms-excel',
244
            'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
245
            'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
246
            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
247
            'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
248
            'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
249
            'xml' => 'text/xml',
250
            'xpm' => 'image/x-xpixmap',
251
            'xsl' => 'text/xml',
252
            'xwd' => 'image/x-windowdump',
253
            'xyz' => 'chemical/x-xyz',
254
            'zip' => 'application/zip',
255
        ];
256
257
        if ($filename === true) {
258
            return $mime_types;
259
        }
260
261
        //get the extension of the file
262
        $extension = explode('.', $filename);
263
264
        //$filename will be an array if a . was found
265
        if (is_array($extension)) {
266
            $extension = strtolower($extension[count($extension) - 1]);
267
        } else {
268
            //file without extension
269
            $extension = 'empty';
270
        }
271
272
        //if the extension is found, return the content type
273
        if (isset($mime_types[$extension])) {
274
            return $mime_types[$extension];
275
        }
276
277
        //else return octet-stream
278
        return 'application/octet-stream';
279
    }
280
281
    /**
282
     * This function streams a file to the client.
283
     *
284
     * @param string $full_file_name
285
     * @param bool   $forced
286
     * @param string $name
287
     * @param bool   $fixLinksHttpToHttps change file content from http to https
288
     *
289
     * @return false if file doesn't exist, true if stream succeeded
290
     */
291
    public static function file_send_for_download(
292
        $full_file_name,
293
        $forced = false,
294
        $name = '',
295
        $fixLinksHttpToHttps = false
296
    ) {
297
        session_write_close(); //we do not need write access to session anymore
298
        if (!is_file($full_file_name)) {
299
            return false;
300
        }
301
        $filename = $name == '' ? basename($full_file_name) : api_replace_dangerous_char($name);
302
        $len = filesize($full_file_name);
303
        // Fixing error when file name contains a ","
304
        $filename = str_replace(',', '', $filename);
305
        $sendFileHeaders = api_get_configuration_value('enable_x_sendfile_headers');
306
307
        // Allows chrome to make videos and audios seekable
308
        header('Accept-Ranges: bytes');
309
310
        if ($forced) {
311
            // Force the browser to save the file instead of opening it
312
            if (isset($sendFileHeaders) &&
313
                !empty($sendFileHeaders)) {
314
                header("X-Sendfile: $filename");
315
            }
316
317
            header('Content-type: application/octet-stream');
318
            header('Content-length: '.$len);
319
            if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
320
                header('Content-Disposition: filename= '.$filename);
321
            } else {
322
                header('Content-Disposition: attachment; filename= '.$filename);
323
            }
324
            if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
325
                header('Pragma: ');
326
                header('Cache-Control: ');
327
                header('Cache-Control: public'); // IE cannot download from sessions without a cache
328
            }
329
            header('Content-Description: '.$filename);
330
            header('Content-Transfer-Encoding: binary');
331
332
            if (function_exists('ob_end_clean') && ob_get_length()) {
333
                // Use ob_end_clean() to avoid weird buffering situations
334
                // where file is sent broken/incomplete for download
335
                ob_end_clean();
336
            }
337
338
            $res = fopen($full_file_name, 'r');
339
            fpassthru($res);
340
341
            return true;
342
        } else {
343
            // no forced download, just let the browser decide what to do according to the mimetype
344
            $lpFixedEncoding = api_get_configuration_value('lp_fixed_encoding');
345
346
            // Commented to let courses content to be cached in order to improve performance:
347
            //header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
348
            //header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
349
350
            // Commented to avoid double caching declaration when playing with IE and HTTPS
351
            //header('Cache-Control: no-cache, must-revalidate');
352
            //header('Pragma: no-cache');
353
354
            $contentType = self::file_get_mime_type($filename);
355
356
            switch ($contentType) {
357
                case 'text/html':
358
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
359
                        $contentType .= '; charset=UTF-8';
360
                    } else {
361
                        $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
362
                        if (!empty($encoding)) {
363
                            $contentType .= '; charset='.$encoding;
364
                        }
365
                    }
366
                    break;
367
                case 'text/plain':
368
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
369
                        $contentType .= '; charset=UTF-8';
370
                    } else {
371
                        $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
372
                        if (!empty($encoding)) {
373
                            $contentType .= '; charset='.$encoding;
374
                        }
375
                    }
376
                    break;
377
                case 'application/vnd.dwg':
378
                case 'application/vnd.dwf':
379
                    header('Content-type: application/octet-stream');
380
                    break;
381
            }
382
383
            header('Content-type: '.$contentType);
384
            header('Content-Length: '.$len);
385
            $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);
386
387
            if (strpos($userAgent, 'msie')) {
388
                header('Content-Disposition: ; filename= '.$filename);
389
            } else {
390
                //header('Content-Disposition: inline');
391
                header('Content-Disposition: inline;');
392
            }
393
394
            if ($fixLinksHttpToHttps) {
395
                $content = file_get_contents($full_file_name);
396
                $content = str_replace(
397
                    ['http%3A%2F%2F', 'http://'],
398
                    ['https%3A%2F%2F', 'https://'],
399
                    $content
400
                );
401
                echo $content;
402
            } else {
403
                if (function_exists('ob_end_clean') && ob_get_length()) {
404
                    // Use ob_end_clean() to avoid weird buffering situations
405
                    // where file is sent broken/incomplete for download
406
                    ob_end_clean();
407
                }
408
409
                readfile($full_file_name);
410
            }
411
412
            return true;
413
        }
414
    }
415
416
    /**
417
     * Session folder filters.
418
     *
419
     * @param string $path
420
     * @param int    $sessionId
421
     *
422
     * @return null|string
423
     */
424
    public static function getSessionFolderFilters($path, $sessionId)
425
    {
426
        $sessionId = intval($sessionId);
427
        $condition = null;
428
429
        if (!empty($sessionId)) {
430
            // Chat folder filter
431
            if ($path == '/chat_files') {
432
                $condition .= " AND (docs.session_id = '$sessionId') ";
433
            }
434
            // share_folder filter
435
            $condition .= " AND docs.path != '/shared_folder' ";
436
        }
437
438
        return $condition;
439
    }
440
441
    /**
442
     * Fetches all document data for the given user/group.
443
     *
444
     * @param array  $courseInfo
445
     * @param string $path
446
     * @param int    $toGroupId       iid
447
     * @param int    $toUserId
448
     * @param bool   $canSeeInvisible
449
     * @param bool   $search
450
     * @param int    $sessionId
451
     *
452
     * @return array with all document data
453
     */
454
    public static function getAllDocumentData(
455
        $courseInfo,
456
        $path = '/',
457
        $toGroupId = 0,
458
        $toUserId = null,
459
        $canSeeInvisible = false,
460
        $search = false,
461
        $sessionId = 0
462
    ) {
463
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
464
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
465
466
        $userGroupFilter = '';
467
        if (!is_null($toUserId)) {
468
            $toUserId = intval($toUserId);
469
            $userGroupFilter = "last.to_user_id = $toUserId";
470
            if (empty($toUserId)) {
471
                $userGroupFilter = " (last.to_user_id = 0 OR last.to_user_id IS NULL) ";
472
            }
473
        } else {
474
            $toGroupId = intval($toGroupId);
475
            $userGroupFilter = "last.to_group_id = $toGroupId";
476
            if (empty($toGroupId)) {
477
                $userGroupFilter = "( last.to_group_id = 0 OR last.to_group_id IS NULL) ";
478
            }
479
        }
480
481
        // Escape underscores in the path so they don't act as a wildcard
482
        $originalPath = $path;
483
        $path = str_replace('_', '\_', $path);
484
485
        $visibilityBit = ' <> 2';
486
487
        // The given path will not end with a slash, unless it's the root '/'
488
        // so no root -> add slash
489
        $addedSlash = $path == '/' ? '' : '/';
490
491
        // Condition for the session
492
        $sessionId = $sessionId ?: api_get_session_id();
493
        $conditionSession = " AND (last.session_id = '$sessionId' OR (last.session_id = '0' OR last.session_id IS NULL) )";
494
        $conditionSession .= self::getSessionFolderFilters($originalPath, $sessionId);
495
496
        $sharedCondition = null;
497
        if ($originalPath == '/shared_folder') {
498
            $students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
499
            if (!empty($students)) {
500
                $conditionList = [];
501
                foreach ($students as $studentInfo) {
502
                    $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
503
                }
504
                $sharedCondition .= ' AND docs.path IN ("'.implode('","', $conditionList).'")';
505
            }
506
        }
507
508
        $sql = "SELECT
509
                    docs.id,
510
                    docs.filetype,
511
                    docs.path,
512
                    docs.title,
513
                    docs.comment,
514
                    docs.size,
515
                    docs.readonly,
516
                    docs.session_id,
517
                    last.session_id item_property_session_id,
518
                    last.lastedit_date,
519
                    last.visibility,
520
                    last.insert_user_id
521
                FROM $tblItemProperty AS last
522
                INNER JOIN $tblDocument AS docs
523
                ON (
524
                    docs.id = last.ref AND
525
                    docs.c_id = last.c_id
526
                )
527
                WHERE                                
528
                    last.tool = '".TOOL_DOCUMENT."' AND 
529
                    docs.c_id = {$courseInfo['real_id']} AND
530
                    last.c_id = {$courseInfo['real_id']} AND
531
                    docs.path LIKE '".Database::escape_string($path.$addedSlash.'%')."' AND
532
                    docs.path NOT LIKE '".Database::escape_string($path.$addedSlash.'%/%')."' AND
533
                    docs.path NOT LIKE '%_DELETED_%' AND
534
                    $userGroupFilter AND
535
                    last.visibility $visibilityBit
536
                    $conditionSession
537
                    $sharedCondition
538
                ORDER BY last.iid DESC, last.session_id DESC
539
                ";
540
        $result = Database::query($sql);
541
542
        $documentData = [];
543
        $isAllowedToEdit = api_is_allowed_to_edit(null, true);
544
        $isCoach = api_is_coach();
545
        if ($result !== false && Database::num_rows($result) != 0) {
546
            $rows = [];
547
548
            $hideInvisibleDocuments = api_get_configuration_value('hide_invisible_course_documents_in_sessions');
549
550
            while ($row = Database::fetch_array($result, 'ASSOC')) {
551
                if (isset($rows[$row['id']])) {
552
                    continue;
553
                }
554
555
                // If we are in session and hide_invisible_course_documents_in_sessions is enabled
556
                // Then we avoid the documents that have visibility in session but that they come from a base course
557
                if ($hideInvisibleDocuments && $sessionId) {
558
                    if ($row['item_property_session_id'] == $sessionId && empty($row['session_id'])) {
559
                        continue;
560
                    }
561
                }
562
563
                $rows[$row['id']] = $row;
564
            }
565
566
            // If we are in session and hide_invisible_course_documents_in_sessions is enabled
567
            // Or if we are students
568
            // Then don't list the invisible or deleted documents
569
            if (($sessionId && $hideInvisibleDocuments) || (!$isCoach && !$isAllowedToEdit)) {
570
                $rows = array_filter($rows, function ($row) {
571
                    if (in_array($row['visibility'], ['0', '2'])) {
572
                        return false;
573
                    }
574
575
                    return true;
576
                });
577
            }
578
579
            foreach ($rows as $row) {
580
                if ($row['filetype'] == 'file' &&
581
                    pathinfo($row['path'], PATHINFO_EXTENSION) == 'html'
582
                ) {
583
                    // Templates management
584
                    $tblTemplate = Database::get_main_table(TABLE_MAIN_TEMPLATES);
585
                    $sql = "SELECT id FROM $tblTemplate
586
                            WHERE
587
                                c_id = '".$courseInfo['real_id']."' AND
588
                                user_id = '".api_get_user_id()."' AND
589
                                ref_doc = '".$row['id']."'";
590
                    $templateResult = Database::query($sql);
591
                    $row['is_template'] = (Database::num_rows($templateResult) > 0) ? 1 : 0;
592
                }
593
                $row['basename'] = basename($row['path']);
594
                // Just filling $document_data.
595
                $documentData[$row['id']] = $row;
596
            }
597
598
            // Only for the student we filter the results see BT#1652
599
            if (!$isCoach && !$isAllowedToEdit) {
600
                // Checking parents visibility.
601
                $finalDocumentData = [];
602
                foreach ($documentData as $row) {
603
                    $isVisible = self::check_visibility_tree(
604
                        $row['id'],
605
                        $courseInfo['code'],
606
                        $sessionId,
607
                        api_get_user_id(),
608
                        $toGroupId
609
                    );
610
                    if ($isVisible) {
611
                        $finalDocumentData[$row['id']] = $row;
612
                    }
613
                }
614
            } else {
615
                $finalDocumentData = $documentData;
616
            }
617
618
            return $finalDocumentData;
619
        } else {
620
            return [];
621
        }
622
    }
623
624
    /**
625
     * Gets the paths of all folders in a course
626
     * can show all folders (except for the deleted ones) or only visible ones.
627
     *
628
     * @param array  $_course
629
     * @param int    $groupIid          iid
630
     * @param bool   $can_see_invisible
631
     * @param bool   $getInvisibleList
632
     * @param string $path              current path
633
     *
634
     * @return array with paths
635
     */
636
    public static function get_all_document_folders(
637
        $_course,
638
        $groupIid = 0,
639
        $can_see_invisible = false,
640
        $getInvisibleList = false,
641
        $path = ''
642
    ) {
643
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
644
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
645
        $groupIid = intval($groupIid);
646
        $document_folders = [];
647
648
        $students = CourseManager::get_user_list_from_course_code(
649
            $_course['code'],
650
            api_get_session_id()
651
        );
652
653
        $conditionList = [];
654
        if (!empty($students)) {
655
            foreach ($students as $studentId => $studentInfo) {
656
                $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
657
            }
658
        }
659
660
        $groupCondition = " last.to_group_id = $groupIid";
661
        if (empty($groupIid)) {
662
            $groupCondition = " (last.to_group_id = 0 OR last.to_group_id IS NULL)";
663
        }
664
665
        $show_users_condition = '';
666
        if (api_get_setting('show_users_folders') === 'false') {
667
            $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
668
        }
669
670
        if ($can_see_invisible) {
671
            // condition for the session
672
            $session_id = api_get_session_id();
673
            //$condition_session = api_get_session_condition($session_id, true, false, 'docs.session_id');
674
675
            $session_id = $session_id ?: api_get_session_id();
676
            $condition_session = " AND (last.session_id = '$session_id' OR (last.session_id = '0' OR last.session_id IS NULL) )";
677
            $condition_session .= self::getSessionFolderFilters($path, $session_id);
678
679
            if ($groupIid != 0) {
680
                $sql = "SELECT DISTINCT docs.id, path
681
                       FROM $TABLE_ITEMPROPERTY  AS last
682
                       INNER JOIN $TABLE_DOCUMENT  AS docs
683
                       ON (
684
                            docs.id = last.ref AND
685
                            docs.c_id = last.c_id
686
                       )
687
                       WHERE                       
688
                            last.tool = '".TOOL_DOCUMENT."' AND
689
                            last.c_id = {$_course['real_id']} AND
690
                            docs.c_id = {$_course['real_id']} AND
691
                            docs.filetype = 'folder' AND
692
                            $groupCondition AND
693
                            docs.path NOT LIKE '%shared_folder%' AND
694
                            docs.path NOT LIKE '%_DELETED_%' AND
695
                            last.visibility <> 2                            
696
                            $condition_session ";
697
            } else {
698
                $sql = "SELECT DISTINCT docs.id, path
699
                        FROM $TABLE_ITEMPROPERTY  AS last
700
                        INNER JOIN $TABLE_DOCUMENT  AS docs
701
                        ON (
702
                            docs.id = last.ref AND
703
                            docs.c_id = last.c_id                          
704
                        )
705
                        WHERE
706
                            last.tool = '".TOOL_DOCUMENT."' AND
707
                            last.c_id = {$_course['real_id']} AND
708
                            docs.c_id = {$_course['real_id']} AND
709
                            docs.filetype = 'folder' AND
710
                            docs.path NOT LIKE '%_DELETED_%' AND
711
                            $groupCondition AND
712
                            last.visibility <> 2
713
                            $show_users_condition 
714
                            $condition_session 
715
                        ";
716
            }
717
            $result = Database::query($sql);
718
719
            if ($result && Database::num_rows($result) != 0) {
720
                while ($row = Database::fetch_array($result, 'ASSOC')) {
721
                    if (self::is_folder_to_avoid($row['path'])) {
722
                        continue;
723
                    }
724
725
                    if (strpos($row['path'], '/shared_folder/') !== false) {
726
                        if (!in_array($row['path'], $conditionList)) {
727
                            continue;
728
                        }
729
                    }
730
731
                    $document_folders[$row['id']] = $row['path'];
732
                }
733
734
                if (!empty($document_folders)) {
735
                    natsort($document_folders);
736
                }
737
738
                return $document_folders;
739
            } else {
740
                return false;
741
            }
742
        } else {
743
            // No invisible folders
744
            // Condition for the session
745
            $session_id = api_get_session_id();
746
            $condition_session = api_get_session_condition(
747
                $session_id,
748
                true,
749
                false,
750
                'docs.session_id'
751
            );
752
753
            $visibilityCondition = 'last.visibility = 1';
754
            $fileType = "docs.filetype = 'folder' AND";
755
            if ($getInvisibleList) {
756
                $visibilityCondition = 'last.visibility = 0';
757
                $fileType = '';
758
            }
759
760
            //get visible folders
761
            $sql = "SELECT DISTINCT docs.id, path
762
                    FROM
763
                    $TABLE_ITEMPROPERTY AS last 
764
                    INNER JOIN $TABLE_DOCUMENT AS docs
765
                    ON (docs.id = last.ref AND last.c_id = docs.c_id)
766
                    WHERE
767
                        $fileType
768
                        last.tool = '".TOOL_DOCUMENT."' AND
769
                        $groupCondition AND
770
                        $visibilityCondition
771
                        $show_users_condition
772
                        $condition_session AND
773
                        last.c_id = {$_course['real_id']}  AND
774
                        docs.c_id = {$_course['real_id']} ";
775
776
            $result = Database::query($sql);
777
778
            $visibleFolders = [];
779
            while ($row = Database::fetch_array($result, 'ASSOC')) {
780
                $visibleFolders[$row['id']] = $row['path'];
781
            }
782
783
            if ($getInvisibleList) {
784
                return $visibleFolders;
785
            }
786
787
            //get invisible folders
788
            $sql = "SELECT DISTINCT docs.id, path
789
                    FROM $TABLE_ITEMPROPERTY AS last 
790
                    INNER JOIN $TABLE_DOCUMENT AS docs
791
                    ON (docs.id = last.ref AND last.c_id = docs.c_id)
792
                    WHERE                        
793
                        docs.filetype = 'folder' AND
794
                        last.tool = '".TOOL_DOCUMENT."' AND
795
                        $groupCondition AND
796
                        last.visibility = 0 $condition_session AND
797
                        last.c_id = {$_course['real_id']} AND
798
                        docs.c_id = {$_course['real_id']} ";
799
            $result = Database::query($sql);
800
            $invisibleFolders = [];
801
            while ($row = Database::fetch_array($result, 'ASSOC')) {
802
                //get visible folders in the invisible ones -> they are invisible too
803
                $sql = "SELECT DISTINCT docs.id, path
804
                        FROM $TABLE_ITEMPROPERTY AS last 
805
                        INNER JOIN $TABLE_DOCUMENT AS docs
806
                        ON (docs.id = last.ref AND docs.c_id = last.c_id)
807
                        WHERE                            
808
                            docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
809
                            docs.filetype = 'folder' AND
810
                            last.tool = '".TOOL_DOCUMENT."' AND
811
                            $groupCondition AND
812
                            last.visibility = 1 $condition_session AND
813
                            last.c_id = {$_course['real_id']} AND
814
                            docs.c_id = {$_course['real_id']}  ";
815
                $folder_in_invisible_result = Database::query($sql);
816
                while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
817
                    $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
818
                }
819
            }
820
821
            // If both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
822
            if (is_array($visibleFolders) && is_array($invisibleFolders)) {
823
                $document_folders = array_diff($visibleFolders, $invisibleFolders);
824
                natsort($document_folders);
825
826
                return $document_folders;
827
            } elseif (is_array($visibleFolders)) {
828
                natsort($visibleFolders);
829
830
                return $visibleFolders;
831
            } else {
832
                //no visible folders found
833
                return false;
834
            }
835
        }
836
    }
837
838
    /**
839
     * This check if a document has the readonly property checked, then see if the user
840
     * is the owner of this file, if all this is true then return true.
841
     *
842
     * @param array  $_course
843
     * @param int    $user_id     id of the current user
844
     * @param string $file        path stored in the database (if not defined, $documentId must be used)
845
     * @param int    $document_id in case you dont have the file path ,
846
     *                            insert the id of the file here and leave $file in blank ''
847
     * @param bool   $to_delete
848
     * @param int    $sessionId
849
     *
850
     * @return bool true/false
851
     * */
852
    public static function check_readonly(
853
        $_course,
854
        $user_id,
855
        $file = null,
856
        $document_id = 0,
857
        $to_delete = false,
858
        $sessionId = null,
859
        $documentId = null
860
    ) {
861
        if (empty($sessionId)) {
862
            $sessionId = api_get_session_id();
863
        } else {
864
            $sessionId = intval($sessionId);
865
        }
866
867
        if (empty($document_id) || !is_numeric($document_id)) {
868
            $document_id = self::get_document_id($_course, $file, $sessionId);
869
        } else {
870
            $document_id = intval($document_id);
871
        }
872
873
        $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
874
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
875
        $course_id = $_course['real_id'];
876
877
        if ($to_delete) {
878
            if (self::is_folder($_course, $document_id)) {
879
                if (!empty($file)) {
880
                    $path = Database::escape_string($file);
881
                    // Check
882
                    $sql = "SELECT td.id, readonly, tp.insert_user_id
883
                            FROM $TABLE_DOCUMENT td 
884
                            INNER JOIN $TABLE_PROPERTY tp
885
                            ON (td.c_id = tp.c_id AND tp.ref= td.id)
886
                            WHERE
887
                                td.c_id = $course_id AND
888
                                tp.c_id = $course_id AND
889
                                td.session_id = $sessionId AND                                
890
                                (path='".$path."' OR path LIKE BINARY '".$path."/%' ) ";
891
                    // Get all id's of documents that are deleted
892
                    $what_to_check_result = Database::query($sql);
893
894
                    if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
895
                        // file with readonly set to 1 exist?
896
                        $readonly_set = false;
897
                        while ($row = Database::fetch_array($what_to_check_result)) {
898
                            //query to delete from item_property table
899
                            if ($row['readonly'] == 1) {
900
                                if (!($row['insert_user_id'] == $user_id)) {
901
                                    $readonly_set = true;
902
                                    break;
903
                                }
904
                            }
905
                        }
906
907
                        if ($readonly_set) {
908
                            return true;
909
                        }
910
                    }
911
                }
912
913
                return false;
914
            }
915
        }
916
917
        if (!empty($document_id)) {
918
            $sql = "SELECT a.insert_user_id, b.readonly
919
                   FROM $TABLE_PROPERTY a 
920
                   INNER JOIN $TABLE_DOCUMENT b
921
                   ON (a.c_id = b.c_id AND a.ref= b.id)
922
                   WHERE
923
            			a.c_id = $course_id AND
924
                        b.c_id = $course_id AND
925
            			a.ref = $document_id 
926
                    LIMIT 1";
927
            $result = Database::query($sql);
928
            $doc_details = Database::fetch_array($result, 'ASSOC');
929
930
            if ($doc_details['readonly'] == 1) {
931
                return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
932
            }
933
        }
934
935
        return false;
936
    }
937
938
    /**
939
     * This check if a document is a folder or not.
940
     *
941
     * @param array $_course
942
     * @param int   $id      document id
943
     *
944
     * @return bool true/false
945
     * */
946
    public static function is_folder($_course, $id)
947
    {
948
        $table = Database::get_course_table(TABLE_DOCUMENT);
949
        if (empty($_course)) {
950
            return false;
951
        }
952
        $course_id = $_course['real_id'];
953
        $id = (int) $id;
954
        $sql = "SELECT filetype FROM $table
955
                WHERE c_id = $course_id AND id= $id";
956
        $result = Database::fetch_array(Database::query($sql), 'ASSOC');
957
958
        return $result['filetype'] == 'folder';
959
    }
960
961
    /**
962
     * @param int   $document_id
963
     * @param array $course_info
964
     * @param int   $session_id
965
     * @param bool  $remove_content_from_db
966
     */
967
    public static function deleteDocumentFromDb(
968
        $document_id,
969
        $course_info = [],
970
        $session_id = 0,
971
        $remove_content_from_db = false
972
    ) {
973
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
974
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
975
976
        // Deleting from the DB
977
        $user_id = api_get_user_id();
978
        $document_id = intval($document_id);
979
980
        if (empty($course_info)) {
981
            $course_info = api_get_course_info();
982
        }
983
984
        if (empty($session_id)) {
985
            $session_id = api_get_session_id();
986
        }
987
        // Soft DB delete
988
        api_item_property_update(
989
            $course_info,
990
            TOOL_DOCUMENT,
991
            $document_id,
992
            'delete',
993
            $user_id,
994
            null,
995
            null,
996
            null,
997
            null,
998
            $session_id
999
        );
1000
        self::delete_document_from_search_engine($course_info['code'], $document_id);
1001
        self::unsetDocumentAsTemplate($document_id, $course_info['real_id'], $user_id);
1002
1003
        //Hard DB delete
1004
        if ($remove_content_from_db) {
1005
            $sql = "DELETE FROM $TABLE_ITEMPROPERTY
1006
                    WHERE
1007
                        c_id = {$course_info['real_id']} AND
1008
                        ref = ".$document_id." AND
1009
                        tool='".TOOL_DOCUMENT."'";
1010
            Database::query($sql);
1011
1012
            $sql = "DELETE FROM $TABLE_DOCUMENT
1013
                    WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
1014
            Database::query($sql);
1015
        }
1016
    }
1017
1018
    /**
1019
     * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
1020
     * Files/folders that are inside a deleted folder get visibility 2.
1021
     *
1022
     * @param array  $_course
1023
     * @param string $path          Path stored in the database
1024
     * @param string $base_work_dir Path to the documents folder (if not defined, $documentId must be used)
1025
     * @param int    $sessionId     The ID of the session, if any
1026
     * @param int    $documentId    The document id, if available
1027
     * @param int    $groupId       iid
1028
     *
1029
     * @return bool true/false
1030
     *
1031
     * @todo now only files/folders in a folder get visibility 2, we should rename them too.
1032
     * @todo We should be able to get rid of this later when using only documentId (check further usage)
1033
     */
1034
    public static function delete_document(
1035
        $_course,
1036
        $path = null,
1037
        $base_work_dir = null,
1038
        $sessionId = null,
1039
        $documentId = null,
1040
        $groupId = 0
1041
    ) {
1042
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1043
1044
        $groupId = intval($groupId);
1045
        if (empty($groupId)) {
1046
            $groupId = api_get_group_id();
1047
        }
1048
1049
        $sessionId = intval($sessionId);
1050
        if (empty($sessionId)) {
1051
            $sessionId = api_get_session_id();
1052
        }
1053
1054
        $course_id = $_course['real_id'];
1055
1056
        if (empty($course_id)) {
1057
            return false;
1058
        }
1059
1060
        if (empty($base_work_dir)) {
1061
            return false;
1062
        }
1063
1064
        if (empty($documentId)) {
1065
            $documentId = self::get_document_id($_course, $path, $sessionId);
1066
            $docInfo = self::get_document_data_by_id(
1067
                $documentId,
1068
                $_course['code'],
1069
                false,
1070
                $sessionId
1071
            );
1072
            $path = $docInfo['path'];
1073
        } else {
1074
            $docInfo = self::get_document_data_by_id(
1075
                $documentId,
1076
                $_course['code'],
1077
                false,
1078
                $sessionId
1079
            );
1080
            if (empty($docInfo)) {
1081
                return false;
1082
            }
1083
            $path = $docInfo['path'];
1084
        }
1085
1086
        $documentId = intval($documentId);
1087
1088
        if (empty($path) || empty($docInfo) || empty($documentId)) {
1089
            return false;
1090
        }
1091
1092
        $itemInfo = api_get_item_property_info(
1093
            $_course['real_id'],
1094
            TOOL_DOCUMENT,
1095
            $documentId,
1096
            $sessionId,
1097
            $groupId
1098
        );
1099
1100
        if (empty($itemInfo)) {
1101
            return false;
1102
        }
1103
1104
        // File was already deleted.
1105
        if ($itemInfo['lastedit_type'] == 'DocumentDeleted' ||
1106
            $itemInfo['lastedit_type'] == 'delete' ||
1107
            $itemInfo['visibility'] == 2
1108
        ) {
1109
            return false;
1110
        }
1111
1112
        // Filtering by group.
1113
        if ($itemInfo['to_group_id'] != $groupId) {
1114
            return false;
1115
        }
1116
1117
        $document_exists_in_disk = file_exists($base_work_dir.$path);
1118
        $new_path = $path.'_DELETED_'.$documentId;
1119
1120
        $file_deleted_from_db = false;
1121
        $file_deleted_from_disk = false;
1122
        $file_renamed_from_disk = false;
1123
1124
        if ($documentId) {
1125
            // Deleting doc from the DB.
1126
            self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1127
            // Checking
1128
            // $file_exists_in_db = self::get_document_data_by_id($documentId, $_course['code']);
1129
            $file_deleted_from_db = true;
1130
        }
1131
1132
        // Looking for children.
1133
        if ($docInfo['filetype'] == 'folder') {
1134
            $cleanPath = Database::escape_string($path);
1135
1136
            // Deleted files inside this folder.
1137
            $sql = "SELECT id FROM $TABLE_DOCUMENT
1138
                    WHERE
1139
                        c_id = $course_id AND
1140
                        session_id = $sessionId AND
1141
                        path LIKE BINARY '".$cleanPath."/%'";
1142
1143
            // Get all id's of documents that are deleted.
1144
            $result = Database::query($sql);
1145
1146
            if ($result && Database::num_rows($result) != 0) {
1147
                // Recursive delete.
1148
                while ($row = Database::fetch_array($result)) {
1149
                    self::delete_document(
1150
                        $_course,
1151
                        null,
1152
                        $base_work_dir,
1153
                        $sessionId,
1154
                        $row['id'],
1155
                        $groupId
1156
                    );
1157
                }
1158
            }
1159
        }
1160
1161
        if ($document_exists_in_disk) {
1162
            if (api_get_setting('permanently_remove_deleted_files') === 'true') {
1163
                // Delete documents, do it like this so metadata gets deleted too
1164
                my_delete($base_work_dir.$path);
1165
                // Hard delete.
1166
                self::deleteDocumentFromDb($documentId, $_course, $sessionId, true);
1167
                $file_deleted_from_disk = true;
1168
            } else {
1169
                // Set visibility to 2 and rename file/folder to xxx_DELETED_#id (soft delete)
1170
                if (is_file($base_work_dir.$path) || is_dir($base_work_dir.$path)) {
1171
                    if (rename($base_work_dir.$path, $base_work_dir.$new_path)) {
1172
                        $new_path = Database::escape_string($new_path);
1173
1174
                        $sql = "UPDATE $TABLE_DOCUMENT
1175
                                SET path = '".$new_path."'
1176
                                WHERE
1177
                                    c_id = $course_id AND
1178
                                    session_id = $sessionId AND
1179
                                    id = ".$documentId;
1180
                        Database::query($sql);
1181
1182
                        // Soft delete.
1183
                        self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1184
1185
                        // Change path of sub folders and documents in database.
1186
                        $old_item_path = $docInfo['path'];
1187
                        $new_item_path = $new_path.substr($old_item_path, strlen($path));
1188
                        $new_item_path = Database::escape_string($new_item_path);
1189
1190
                        $sql = "UPDATE $TABLE_DOCUMENT
1191
                                SET path = '".$new_item_path."'
1192
                                WHERE
1193
                                    c_id = $course_id AND
1194
                                    session_id = $sessionId AND
1195
                                    id = ".$documentId;
1196
                        Database::query($sql);
1197
1198
                        $file_renamed_from_disk = true;
1199
                    } else {
1200
                        // Couldn't rename - file permissions problem?
1201
                        error_log(
1202
                            __FILE__.' '.__LINE__.': Error renaming '.$base_work_dir.$path.' to '.$base_work_dir.$new_path.'. This is probably due to file permissions',
1203
                            0
1204
                        );
1205
                    }
1206
                }
1207
            }
1208
        }
1209
        // Checking inconsistency
1210
        //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').')');
1211
        if ($file_deleted_from_db && $file_deleted_from_disk ||
1212
            $file_deleted_from_db && $file_renamed_from_disk
1213
        ) {
1214
            return true;
1215
        } else {
1216
            //Something went wrong
1217
            //The file or directory isn't there anymore (on the filesystem)
1218
            // This means it has been removed externally. To prevent a
1219
            // blocking error from happening, we drop the related items from the
1220
            // item_property and the document table.
1221
            error_log(
1222
                __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',
1223
                0
1224
            );
1225
1226
            return false;
1227
        }
1228
    }
1229
1230
    /**
1231
     * Removes documents from search engine database.
1232
     *
1233
     * @param string $course_id   Course code
1234
     * @param int    $document_id Document id to delete
1235
     */
1236
    public static function delete_document_from_search_engine($course_id, $document_id)
1237
    {
1238
        // remove from search engine if enabled
1239
        if (api_get_setting('search_enabled') === 'true') {
1240
            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
1241
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1242
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1243
            $res = Database::query($sql);
1244
            if (Database::num_rows($res) > 0) {
1245
                $row2 = Database::fetch_array($res);
1246
                $di = new ChamiloIndexer();
1247
                $di->remove_document($row2['search_did']);
1248
            }
1249
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1250
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1251
            Database::query($sql);
1252
1253
            // remove terms from db
1254
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1255
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $document_id);
1256
        }
1257
    }
1258
1259
    /**
1260
     * Gets the id of a document with a given path.
1261
     *
1262
     * @param array  $courseInfo
1263
     * @param string $path
1264
     * @param int    $sessionId
1265
     *
1266
     * @return int id of document / false if no doc found
1267
     */
1268
    public static function get_document_id($courseInfo, $path, $sessionId = null)
1269
    {
1270
        $table = Database::get_course_table(TABLE_DOCUMENT);
1271
        $courseId = $courseInfo['real_id'];
1272
1273
        if (!isset($sessionId)) {
1274
            $sessionId = api_get_session_id();
1275
        } else {
1276
            $sessionId = intval($sessionId);
1277
        }
1278
1279
        $path = Database::escape_string($path);
1280
        if (!empty($courseId) && !empty($path)) {
1281
            $sql = "SELECT id FROM $table
1282
                    WHERE
1283
                        c_id = $courseId AND
1284
                        path LIKE BINARY '$path' AND
1285
                        session_id = $sessionId
1286
                    LIMIT 1";
1287
1288
            $result = Database::query($sql);
1289
            if (Database::num_rows($result)) {
1290
                $row = Database::fetch_array($result);
1291
1292
                return intval($row['id']);
1293
            }
1294
        }
1295
1296
        return false;
1297
    }
1298
1299
    /**
1300
     * Gets the document data with a given id.
1301
     *
1302
     * @param int    $id            Document Id (id field in c_document table)
1303
     * @param string $course_code   Course code
1304
     * @param bool   $load_parents  load folder parents
1305
     * @param int    $session_id    The session ID,
1306
     *                              0 if requires context *out of* session, and null to use global context
1307
     * @param bool   $ignoreDeleted
1308
     *
1309
     * @return array document content
1310
     */
1311
    public static function get_document_data_by_id(
1312
        $id,
1313
        $course_code,
1314
        $load_parents = false,
1315
        $session_id = null,
1316
        $ignoreDeleted = false
1317
    ) {
1318
        $course_info = api_get_course_info($course_code);
1319
        $course_id = $course_info['real_id'];
1320
1321
        if (empty($course_info)) {
1322
            return false;
1323
        }
1324
1325
        $session_id = empty($session_id) ? api_get_session_id() : (int) $session_id;
1326
        $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
1327
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1328
        $id = (int) $id;
1329
        $sessionCondition = api_get_session_condition($session_id, true, true);
1330
1331
        $sql = "SELECT * FROM $TABLE_DOCUMENT
1332
                WHERE c_id = $course_id $sessionCondition AND id = $id";
1333
1334
        if ($ignoreDeleted) {
1335
            $sql .= " AND path NOT LIKE '%_DELETED_%' ";
1336
        }
1337
1338
        $result = Database::query($sql);
1339
        if ($result && Database::num_rows($result) == 1) {
1340
            $row = Database::fetch_array($result, 'ASSOC');
1341
            //@todo need to clarify the name of the URLs not nice right now
1342
            $url_path = urlencode($row['path']);
1343
            $path = str_replace('%2F', '/', $url_path);
1344
            $pathinfo = pathinfo($row['path']);
1345
1346
            $row['url'] = api_get_path(WEB_CODE_PATH).'document/showinframes.php?cidReq='.$course_code.'&id='.$id;
1347
            $row['document_url'] = api_get_path(WEB_CODE_PATH).'document/document.php?cidReq='.$course_code.'&id='.$id;
1348
            $row['absolute_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
1349
            $row['absolute_path_from_document'] = '/document'.$row['path'];
1350
            $row['absolute_parent_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$pathinfo['dirname'].'/';
1351
            $row['direct_url'] = $www.$path;
1352
            $row['basename'] = basename($row['path']);
1353
1354
            if (dirname($row['path']) == '.') {
1355
                $row['parent_id'] = '0';
1356
            } else {
1357
                $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), $session_id);
1358
            }
1359
            $parents = [];
1360
1361
            //Use to generate parents (needed for the breadcrumb)
1362
            //@todo sorry but this for is here because there's not a parent_id in the document table so we parsed the path!!
1363
            if ($load_parents) {
1364
                $dir_array = explode('/', $row['path']);
1365
                $dir_array = array_filter($dir_array);
1366
                $array_len = count($dir_array) + 1;
1367
                $real_dir = '';
1368
1369
                for ($i = 1; $i < $array_len; $i++) {
1370
                    $real_dir .= '/'.(isset($dir_array[$i]) ? $dir_array[$i] : '');
1371
                    $parent_id = self::get_document_id($course_info, $real_dir);
1372
                    if ($session_id != 0 && empty($parent_id)) {
1373
                        $parent_id = self::get_document_id($course_info, $real_dir, 0);
1374
                    }
1375
                    if (!empty($parent_id)) {
1376
                        $sub_document_data = self::get_document_data_by_id(
1377
                            $parent_id,
1378
                            $course_code,
1379
                            false,
1380
                            $session_id
1381
                        );
1382
                        if ($session_id != 0 and !$sub_document_data) {
1383
                            $sub_document_data = self::get_document_data_by_id(
1384
                                $parent_id,
1385
                                $course_code,
1386
                                false,
1387
                                0
1388
                            );
1389
                        }
1390
                        //@todo add visibility here
1391
                        $parents[] = $sub_document_data;
1392
                    }
1393
                }
1394
            }
1395
            $row['parents'] = $parents;
1396
1397
            return $row;
1398
        }
1399
1400
        return false;
1401
    }
1402
1403
    /**
1404
     * Allow to set a specific document as a new template for CKeditor
1405
     * for a particular user in a particular course.
1406
     *
1407
     * @param string $title
1408
     * @param string $description
1409
     * @param int    $document_id_for_template the document id
1410
     * @param int    $courseId
1411
     * @param int    $user_id
1412
     * @param string $image
1413
     *
1414
     * @return bool
1415
     */
1416
    public static function setDocumentAsTemplate(
1417
        $title,
1418
        $description,
1419
        $document_id_for_template,
1420
        $courseId,
1421
        $user_id,
1422
        $image
1423
    ) {
1424
        // Database table definition
1425
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1426
        $params = [
1427
            'title' => $title,
1428
            'description' => $description,
1429
            'c_id' => $courseId,
1430
            'user_id' => $user_id,
1431
            'ref_doc' => $document_id_for_template,
1432
            'image' => $image,
1433
        ];
1434
        Database::insert($table_template, $params);
1435
1436
        return true;
1437
    }
1438
1439
    /**
1440
     * Unset a document as template.
1441
     *
1442
     * @param int $document_id
1443
     * @param int $courseId
1444
     * @param int $user_id
1445
     */
1446
    public static function unsetDocumentAsTemplate(
1447
        $document_id,
1448
        $courseId,
1449
        $user_id
1450
    ) {
1451
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1452
        $course_code = (int) $courseId;
1453
        $user_id = (int) $user_id;
1454
        $document_id = (int) $document_id;
1455
        $sql = 'SELECT id FROM '.$table_template.'
1456
                WHERE
1457
                    c_id = "'.$course_code.'" AND
1458
                    user_id = "'.$user_id.'" AND
1459
                    ref_doc = "'.$document_id.'"';
1460
        $result = Database::query($sql);
1461
        $template_id = Database::result($result, 0, 0);
1462
1463
        my_delete(api_get_path(SYS_CODE_PATH).'upload/template_thumbnails/'.$template_id.'.jpg');
1464
1465
        $sql = 'DELETE FROM '.$table_template.'
1466
                WHERE
1467
                    c_id ="'.$courseId.'" AND
1468
                    user_id="'.$user_id.'" AND
1469
                    ref_doc="'.$document_id.'"';
1470
1471
        Database::query($sql);
1472
    }
1473
1474
    /**
1475
     * Return true if the documentpath have visibility=1 as
1476
     * item_property (you should use the is_visible_by_id).
1477
     *
1478
     * @param string $doc_path the relative complete path of the document
1479
     * @param array  $course   the _course array info of the document's course
1480
     * @param int
1481
     * @param string
1482
     *
1483
     * @return bool
1484
     */
1485
    public static function is_visible(
1486
        $doc_path,
1487
        $course,
1488
        $session_id = 0,
1489
        $file_type = 'file'
1490
    ) {
1491
        $docTable = Database::get_course_table(TABLE_DOCUMENT);
1492
        $propTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
1493
1494
        $course_id = $course['real_id'];
1495
        // note the extra / at the end of doc_path to match every path in
1496
        // the document table that is part of the document path
1497
1498
        $session_id = intval($session_id);
1499
        $condition = "AND d.session_id IN  ('$session_id', '0') ";
1500
        // The " d.filetype='file' " let the user see a file even if the folder is hidden see #2198
1501
1502
        /*
1503
          When using hotpotatoes files, a new html files are generated
1504
          in the hotpotatoes folder to display the test.
1505
          The genuine html file is copied to math4.htm(user_id).t.html
1506
          Images files are not copied, and keep same name.
1507
          To check the html file visibility, we don't have to check file math4.htm(user_id).t.html but file math4.htm
1508
          In this case, we have to remove (user_id).t.html to check the visibility of the file
1509
          For images, we just check the path of the image file.
1510
1511
          Exemple of hotpotatoes folder :
1512
          A.jpg
1513
          maths4-consigne.jpg
1514
          maths4.htm
1515
          maths4.htm1.t.html
1516
          maths4.htm52.t.html
1517
          maths4.htm654.t.html
1518
          omega.jpg
1519
          theta.jpg
1520
         */
1521
1522
        if (strpos($doc_path, 'HotPotatoes_files') && preg_match("/\.t\.html$/", $doc_path)) {
1523
            $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
1524
        }
1525
1526
        if (!in_array($file_type, ['file', 'folder'])) {
1527
            $file_type = 'file';
1528
        }
1529
        $doc_path = Database::escape_string($doc_path).'/';
1530
1531
        $sql = "SELECT visibility
1532
                FROM $docTable d
1533
                INNER JOIN $propTable ip
1534
                ON (d.id = ip.ref AND d.c_id = ip.c_id)
1535
        		WHERE
1536
        		    d.c_id  = $course_id AND 
1537
        		    ip.c_id = $course_id AND
1538
        		    ip.tool = '".TOOL_DOCUMENT."' $condition AND
1539
        			filetype = '$file_type' AND
1540
        			locate(concat(path,'/'), '$doc_path')=1
1541
                ";
1542
1543
        $result = Database::query($sql);
1544
        $is_visible = false;
1545
        if (Database::num_rows($result) > 0) {
1546
            $row = Database::fetch_array($result, 'ASSOC');
1547
            if ($row['visibility'] == 1) {
1548
                $is_visible = api_is_allowed_in_course() || api_is_platform_admin();
1549
            }
1550
        }
1551
1552
        /* improved protection of documents viewable directly through the url:
1553
            incorporates the same protections of the course at the url of
1554
            documents:
1555
            access allowed for the whole world Open, access allowed for
1556
            users registered on the platform Private access, document accessible
1557
            only to course members (see the Users list), Completely closed;
1558
            the document is only accessible to the course admin and
1559
            teaching assistants.*/
1560
        //return $_SESSION ['is_allowed_in_course'] || api_is_platform_admin();
1561
        return $is_visible;
1562
    }
1563
1564
    /**
1565
     * Return true if user can see a file.
1566
     *
1567
     * @param   int     document id
1568
     * @param   array   course info
1569
     * @param   int
1570
     * @param   int
1571
     * @param bool
1572
     *
1573
     * @return bool
1574
     */
1575
    public static function is_visible_by_id(
1576
        $doc_id,
1577
        $course_info,
1578
        $session_id,
1579
        $user_id,
1580
        $admins_can_see_everything = true,
1581
        $userIsSubscribed = null
1582
    ) {
1583
        $user_in_course = false;
1584
1585
        //1. Checking the course array
1586
        if (empty($course_info)) {
1587
            $course_info = api_get_course_info();
1588
            if (empty($course_info)) {
1589
                return false;
1590
            }
1591
        }
1592
1593
        $doc_id = intval($doc_id);
1594
        $session_id = intval($session_id);
1595
1596
        //2. Course and Session visibility are handle in local.inc.php/global.inc.php
1597
        //3. Checking if user exist in course/session
1598
        if ($session_id == 0) {
1599
            if (is_null($userIsSubscribed)) {
1600
                $userIsSubscribed = CourseManager::is_user_subscribed_in_course(
1601
                    $user_id,
1602
                    $course_info['code']
1603
                );
1604
            }
1605
1606
            if ($userIsSubscribed === true || api_is_platform_admin()) {
1607
                $user_in_course = true;
1608
            }
1609
1610
            // Check if course is open then we can consider that the student is registered to the course
1611
            if (isset($course_info) &&
1612
                in_array(
1613
                    $course_info['visibility'],
1614
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
1615
                )
1616
            ) {
1617
                $user_in_course = true;
1618
            }
1619
        } else {
1620
            $user_status = SessionManager::get_user_status_in_course_session(
1621
                $user_id,
1622
                $course_info['real_id'],
1623
                $session_id
1624
            );
1625
1626
            if (in_array($user_status, ['0', '2', '6'])) {
1627
                //is true if is an student, course session teacher or coach
1628
                $user_in_course = true;
1629
            }
1630
1631
            if (api_is_platform_admin()) {
1632
                $user_in_course = true;
1633
            }
1634
        }
1635
1636
        // 4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
1637
        if ($user_in_course) {
1638
            // 4.1 Checking document visibility for a Course
1639
            if ($session_id == 0) {
1640
                $item_info = api_get_item_property_info(
1641
                    $course_info['real_id'],
1642
                    'document',
1643
                    $doc_id,
1644
                    0
1645
                );
1646
1647
                if (isset($item_info['visibility'])) {
1648
                    // True for admins if document exists
1649
                    if ($admins_can_see_everything && api_is_platform_admin()) {
1650
                        return true;
1651
                    }
1652
                    if ($item_info['visibility'] == 1) {
1653
                        return true;
1654
                    }
1655
                }
1656
            } else {
1657
                // 4.2 Checking document visibility for a Course in a Session
1658
                $item_info = api_get_item_property_info(
1659
                    $course_info['real_id'],
1660
                    'document',
1661
                    $doc_id,
1662
                    0
1663
                );
1664
1665
                $item_info_in_session = api_get_item_property_info(
1666
                    $course_info['real_id'],
1667
                    'document',
1668
                    $doc_id,
1669
                    $session_id
1670
                );
1671
1672
                // True for admins if document exists
1673
                if (isset($item_info['visibility'])) {
1674
                    if ($admins_can_see_everything && api_is_platform_admin()) {
1675
                        return true;
1676
                    }
1677
                }
1678
1679
                if (isset($item_info_in_session['visibility'])) {
1680
                    if ($item_info_in_session['visibility'] == 1) {
1681
                        return true;
1682
                    }
1683
                } else {
1684
                    if ($item_info['visibility'] == 1) {
1685
                        return true;
1686
                    }
1687
                }
1688
            }
1689
        } elseif ($admins_can_see_everything && api_is_platform_admin()) {
1690
            return true;
1691
        }
1692
1693
        return false;
1694
    }
1695
1696
    /**
1697
     * Allow attach a certificate to a course.
1698
     *
1699
     * @todo move to certificate.lib.php
1700
     *
1701
     * @param string $course_id
1702
     * @param int    $document_id
1703
     * @param int    $session_id
1704
     */
1705
    public static function attach_gradebook_certificate($course_id, $document_id, $session_id = 0)
1706
    {
1707
        $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1708
        $session_id = intval($session_id);
1709
        if (empty($session_id)) {
1710
            $session_id = api_get_session_id();
1711
        }
1712
1713
        if (empty($session_id)) {
1714
            $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
1715
        } elseif ($session_id > 0) {
1716
            $sql_session = 'AND session_id='.intval($session_id);
1717
        } else {
1718
            $sql_session = '';
1719
        }
1720
        $sql = 'UPDATE '.$tbl_category.' SET document_id="'.intval($document_id).'"
1721
                WHERE course_code="'.Database::escape_string($course_id).'" '.$sql_session;
1722
        Database::query($sql);
1723
    }
1724
1725
    /**
1726
     * get the document id of default certificate.
1727
     *
1728
     * @todo move to certificate.lib.php
1729
     *
1730
     * @param string $course_id
1731
     * @param int    $session_id
1732
     *
1733
     * @return int The default certificate id
1734
     */
1735
    public static function get_default_certificate_id($course_id, $session_id = 0)
1736
    {
1737
        $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1738
        $session_id = intval($session_id);
1739
        if (empty($session_id)) {
1740
            $session_id = api_get_session_id();
1741
        }
1742
1743
        if (empty($session_id)) {
1744
            $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
1745
        } elseif ($session_id > 0) {
1746
            $sql_session = 'AND session_id='.intval($session_id);
1747
        } else {
1748
            $sql_session = '';
1749
        }
1750
        $sql = 'SELECT document_id FROM '.$tbl_category.'
1751
                WHERE course_code="'.Database::escape_string($course_id).'" '.$sql_session;
1752
1753
        $rs = Database::query($sql);
1754
        $num = Database::num_rows($rs);
1755
        if ($num == 0) {
1756
            return null;
1757
        }
1758
        $row = Database::fetch_array($rs);
1759
1760
        return $row['document_id'];
1761
    }
1762
1763
    /**
1764
     * Allow replace user info in file html.
1765
     *
1766
     * @param int    $user_id
1767
     * @param string $course_code
1768
     * @param int    $sessionId
1769
     * @param bool   $is_preview
1770
     *
1771
     * @return array
1772
     */
1773
    public static function replace_user_info_into_html(
1774
        $user_id,
1775
        $course_code,
1776
        $sessionId,
1777
        $is_preview = false
1778
    ) {
1779
        $user_id = intval($user_id);
1780
        $course_info = api_get_course_info($course_code);
1781
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
1782
        $course_id = $course_info['real_id'];
1783
1784
        $document_id = self::get_default_certificate_id(
1785
            $course_code,
1786
            $sessionId
1787
        );
1788
1789
        $my_content_html = null;
1790
        if ($document_id) {
1791
            $sql = "SELECT path FROM $tbl_document
1792
                    WHERE c_id = $course_id AND id = $document_id";
1793
            $rs = Database::query($sql);
1794
            $new_content = '';
1795
            $all_user_info = [];
1796
            if (Database::num_rows($rs)) {
1797
                $row = Database::fetch_array($rs);
1798
                $filepath = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
1799
                if (is_file($filepath)) {
1800
                    $my_content_html = file_get_contents($filepath);
1801
                }
1802
                $all_user_info = self::get_all_info_to_certificate(
1803
                    $user_id,
1804
                    $course_code,
1805
                    $is_preview
1806
                );
1807
1808
                $info_to_be_replaced_in_content_html = $all_user_info[0];
1809
                $info_to_replace_in_content_html = $all_user_info[1];
1810
                $new_content = str_replace(
1811
                    $info_to_be_replaced_in_content_html,
1812
                    $info_to_replace_in_content_html,
1813
                    $my_content_html
1814
                );
1815
            }
1816
1817
            return [
1818
                'content' => $new_content,
1819
                'variables' => $all_user_info,
1820
            ];
1821
        }
1822
1823
        return [];
1824
    }
1825
1826
    /**
1827
     * Return all content to replace and all content to be replace.
1828
     *
1829
     * @param int  $user_id
1830
     * @param int  $course_id
1831
     * @param bool $is_preview
1832
     *
1833
     * @return array
1834
     */
1835
    public static function get_all_info_to_certificate($user_id, $course_id, $is_preview = false)
1836
    {
1837
        $info_list = [];
1838
        $user_id = intval($user_id);
1839
        $course_info = api_get_course_info($course_id);
1840
1841
        // Portal info
1842
        $organization_name = api_get_setting('Institution');
1843
        $portal_name = api_get_setting('siteName');
1844
1845
        // Extra user data information
1846
        $extra_user_info_data = UserManager::get_extra_user_data(
1847
            $user_id,
1848
            false,
1849
            false,
1850
            false,
1851
            true
1852
        );
1853
1854
        // get extra fields
1855
        $extraField = new ExtraField('user');
1856
        $extraFields = $extraField->get_all(['filter = ? AND visible_to_self = ?' => [1, 1]]);
1857
1858
        // Student information
1859
        $user_info = api_get_user_info($user_id);
1860
        $first_name = $user_info['firstname'];
1861
        $last_name = $user_info['lastname'];
1862
        $username = $user_info['username'];
1863
        $official_code = $user_info['official_code'];
1864
1865
        // Teacher information
1866
        $info_teacher_id = UserManager::get_user_id_of_course_admin_or_session_admin($course_info);
1867
        $teacher_info = api_get_user_info($info_teacher_id);
1868
        $teacher_first_name = $teacher_info['firstname'];
1869
        $teacher_last_name = $teacher_info['lastname'];
1870
1871
        // info gradebook certificate
1872
        $info_grade_certificate = UserManager::get_info_gradebook_certificate($course_id, $user_id);
1873
        $date_certificate = $info_grade_certificate['created_at'];
1874
        $date_long_certificate = '';
1875
1876
        $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
1877
        if (!empty($date_certificate)) {
1878
            $date_long_certificate = api_convert_and_format_date($date_certificate);
1879
            $date_no_time = api_convert_and_format_date($date_certificate, DATE_FORMAT_LONG_NO_DAY);
1880
        }
1881
1882
        if ($is_preview) {
1883
            $date_long_certificate = api_convert_and_format_date(api_get_utc_datetime());
1884
            $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
1885
        }
1886
1887
        $url = api_get_path(WEB_PATH).'certificates/index.php?id='.$info_grade_certificate['id'];
1888
        $externalStyleFile = api_get_path(SYS_CSS_PATH).'themes/'.api_get_visual_theme().'/certificate.css';
1889
        $externalStyle = '';
1890
        if (is_file($externalStyleFile)) {
1891
            $externalStyle = file_get_contents($externalStyleFile);
1892
        }
1893
1894
        // Replace content
1895
        $info_to_replace_in_content_html = [
1896
            $first_name,
1897
            $last_name,
1898
            $username,
1899
            $organization_name,
1900
            $portal_name,
1901
            $teacher_first_name,
1902
            $teacher_last_name,
1903
            $official_code,
1904
            $date_long_certificate,
1905
            $date_no_time,
1906
            $course_id,
1907
            $course_info['name'],
1908
            $info_grade_certificate['grade'],
1909
            $url,
1910
            '<a href="'.$url.'" target="_blank">'.get_lang('CertificateOnlineLink').'</a>',
1911
            '((certificate_barcode))',
1912
            $externalStyle,
1913
        ];
1914
1915
        $tags = [
1916
            '((user_firstname))',
1917
            '((user_lastname))',
1918
            '((user_username))',
1919
            '((gradebook_institution))',
1920
            '((gradebook_sitename))',
1921
            '((teacher_firstname))',
1922
            '((teacher_lastname))',
1923
            '((official_code))',
1924
            '((date_certificate))',
1925
            '((date_certificate_no_time))',
1926
            '((course_code))',
1927
            '((course_title))',
1928
            '((gradebook_grade))',
1929
            '((certificate_link))',
1930
            '((certificate_link_html))',
1931
            '((certificate_barcode))',
1932
            '((external_style))',
1933
        ];
1934
1935
        if (!empty($extraFields)) {
1936
            foreach ($extraFields as $extraField) {
1937
                $valueExtra = isset($extra_user_info_data[$extraField['variable']]) ? $extra_user_info_data[$extraField['variable']] : '';
1938
                $tags[] = '(('.strtolower($extraField['variable']).'))';
1939
                $info_to_replace_in_content_html[] = $valueExtra;
1940
            }
1941
        }
1942
1943
        $info_list[] = $tags;
1944
        $info_list[] = $info_to_replace_in_content_html;
1945
1946
        return $info_list;
1947
    }
1948
1949
    /**
1950
     * Remove default certificate.
1951
     *
1952
     * @param string $course_id              The course code
1953
     * @param int    $default_certificate_id The document id of the default certificate
1954
     */
1955
    public static function remove_attach_certificate($course_id, $default_certificate_id)
1956
    {
1957
        if (empty($default_certificate_id)) {
1958
            return false;
1959
        }
1960
1961
        $default_certificate = self::get_default_certificate_id($course_id);
1962
        if ((int) $default_certificate == (int) $default_certificate_id) {
1963
            $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1964
            $session_id = api_get_session_id();
1965
            if ($session_id == 0 || is_null($session_id)) {
1966
                $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
1967
            } elseif ($session_id > 0) {
1968
                $sql_session = 'AND session_id='.intval($session_id);
1969
            } else {
1970
                $sql_session = '';
1971
            }
1972
1973
            $sql = 'UPDATE '.$tbl_category.' SET document_id = null
1974
                    WHERE
1975
                        course_code = "'.Database::escape_string($course_id).'" AND
1976
                        document_id="'.$default_certificate_id.'" '.$sql_session;
1977
            Database::query($sql);
1978
        }
1979
    }
1980
1981
    /**
1982
     * Create directory certificate.
1983
     *
1984
     * @param array $courseInfo
1985
     */
1986
    public static function create_directory_certificate_in_course($courseInfo)
1987
    {
1988
        if (!empty($courseInfo)) {
1989
            $to_group_id = 0;
1990
            $to_user_id = null;
1991
            $course_dir = $courseInfo['path']."/document/";
1992
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
1993
            $base_work_dir = $sys_course_path.$course_dir;
1994
            $dir_name = '/certificates';
1995
            $post_dir_name = get_lang('CertificatesFiles');
1996
            $visibility_command = 'invisible';
1997
1998
            $id = self::get_document_id_of_directory_certificate();
1999
2000
            if (empty($id)) {
2001
                create_unexisting_directory(
2002
                    $courseInfo,
2003
                    api_get_user_id(),
2004
                    api_get_session_id(),
2005
                    $to_group_id,
2006
                    $to_user_id,
2007
                    $base_work_dir,
2008
                    $dir_name,
2009
                    $post_dir_name,
2010
                    null,
2011
                    false,
2012
                    false
2013
                );
2014
2015
                $id = self::get_document_id_of_directory_certificate();
2016
2017
                if (empty($id)) {
2018
                    $id = add_document(
2019
                        $courseInfo,
2020
                        $dir_name,
2021
                        'folder',
2022
                        0,
2023
                        $post_dir_name,
2024
                        null,
2025
                        0,
2026
                        true,
2027
                        $to_group_id,
2028
                        0,
2029
                        0,
2030
                        false
2031
                    );
2032
                }
2033
2034
                if (!empty($id)) {
2035
                    api_item_property_update(
2036
                        $courseInfo,
2037
                        TOOL_DOCUMENT,
2038
                        $id,
2039
                        $visibility_command,
2040
                        api_get_user_id()
2041
                    );
2042
                }
2043
            }
2044
        }
2045
    }
2046
2047
    /**
2048
     * Get the document id of the directory certificate.
2049
     *
2050
     * @return int The document id of the directory certificate
2051
     *
2052
     * @todo move to certificate.lib.php
2053
     */
2054
    public static function get_document_id_of_directory_certificate()
2055
    {
2056
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
2057
        $course_id = api_get_course_int_id();
2058
        $sql = "SELECT id FROM $tbl_document 
2059
                WHERE c_id = $course_id AND path='/certificates' ";
2060
        $rs = Database::query($sql);
2061
        $row = Database::fetch_array($rs);
2062
2063
        return $row['id'];
2064
    }
2065
2066
    /**
2067
     * Check if a directory given is for certificate.
2068
     *
2069
     * @todo move to certificate.lib.php
2070
     *
2071
     * @param string $dir path of directory
2072
     *
2073
     * @return bool true if is a certificate or false otherwise
2074
     */
2075
    public static function is_certificate_mode($dir)
2076
    {
2077
        // I'm in the certification module?
2078
        $is_certificate_mode = false;
2079
        $is_certificate_array = explode('/', $dir);
2080
        array_shift($is_certificate_array);
2081
        if (isset($is_certificate_array[0]) && $is_certificate_array[0] == 'certificates') {
2082
            $is_certificate_mode = true;
2083
        }
2084
2085
        return $is_certificate_mode || (isset($_GET['certificate']) && $_GET['certificate'] === 'true');
2086
    }
2087
2088
    /**
2089
     * Gets the list of included resources as a list of absolute or relative paths from a html file or string html
2090
     * This allows for a better SCORM export or replace urls inside content html from copy course
2091
     * The list will generally include pictures, flash objects, java applets, or any other
2092
     * stuff included in the source of the current item. The current item is expected
2093
     * to be an HTML file or string html. If it is not, then the function will return and empty list.
2094
     *
2095
     * @param    string  source html (content or path)
2096
     * @param    bool    is file or string html
2097
     * @param    string    type (one of the app tools) - optional (otherwise takes the current item's type)
2098
     * @param    int        level of recursivity we're in
2099
     *
2100
     * @return array List of file paths. An additional field containing 'local' or 'remote' helps determine
2101
     *               if the file should be copied into the zip or just linked
2102
     */
2103
    public static function get_resources_from_source_html(
2104
        $source_html,
2105
        $is_file = false,
2106
        $type = null,
2107
        $recursivity = 1
2108
    ) {
2109
        $max = 5;
2110
        $attributes = [];
2111
        $wanted_attributes = [
2112
            'src',
2113
            'url',
2114
            '@import',
2115
            'href',
2116
            'value',
2117
            'flashvars',
2118
            'poster',
2119
        ];
2120
        $explode_attributes = ['flashvars' => 'file'];
2121
        $abs_path = '';
2122
2123
        if ($recursivity > $max) {
2124
            return [];
2125
        }
2126
2127
        if (!isset($type)) {
2128
            $type = TOOL_DOCUMENT;
2129
        }
2130
2131
        if (!$is_file) {
2132
            $attributes = self::parse_HTML_attributes(
2133
                $source_html,
2134
                $wanted_attributes,
2135
                $explode_attributes
2136
            );
2137
        } else {
2138
            if (is_file($source_html)) {
2139
                $abs_path = $source_html;
2140
                //for now, read the whole file in one go (that's gonna be a problem when the file is too big)
2141
                $info = pathinfo($abs_path);
2142
                $ext = $info['extension'];
2143
                switch (strtolower($ext)) {
2144
                    case 'html':
2145
                    case 'htm':
2146
                    case 'shtml':
2147
                    case 'css':
2148
                        $file_content = file_get_contents($abs_path);
2149
                        // get an array of attributes from the HTML source
2150
                        $attributes = self::parse_HTML_attributes(
2151
                            $file_content,
2152
                            $wanted_attributes,
2153
                            $explode_attributes
2154
                        );
2155
                        break;
2156
                    default:
2157
                        break;
2158
                }
2159
            } else {
2160
                return false;
2161
            }
2162
        }
2163
2164
        $files_list = [];
2165
        switch ($type) {
2166
            case TOOL_DOCUMENT:
2167
            case TOOL_QUIZ:
2168
            case 'sco':
2169
                foreach ($wanted_attributes as $attr) {
2170
                    if (isset($attributes[$attr])) {
2171
                        //find which kind of path these are (local or remote)
2172
                        $sources = $attributes[$attr];
2173
                        foreach ($sources as $source) {
2174
                            //skip what is obviously not a resource
2175
                            if (strpos($source, '+this.')) {
2176
                                continue; //javascript code - will still work unaltered
2177
                            }
2178
                            if (strpos($source, '.') === false) {
2179
                                continue; //no dot, should not be an external file anyway
2180
                            }
2181
                            if (strpos($source, 'mailto:')) {
2182
                                continue; //mailto link
2183
                            }
2184
                            if (strpos($source, ';') && !strpos($source, '&amp;')) {
2185
                                continue; //avoid code - that should help
2186
                            }
2187
2188
                            if ($attr == 'value') {
2189
                                if (strpos($source, 'mp3file')) {
2190
                                    $files_list[] = [
2191
                                        substr($source, 0, strpos($source, '.swf') + 4),
2192
                                        'local',
2193
                                        'abs',
2194
                                    ];
2195
                                    $mp3file = substr($source, strpos($source, 'mp3file=') + 8);
2196
                                    if (substr($mp3file, 0, 1) == '/') {
2197
                                        $files_list[] = [$mp3file, 'local', 'abs'];
2198
                                    } else {
2199
                                        $files_list[] = [$mp3file, 'local', 'rel'];
2200
                                    }
2201
                                } elseif (strpos($source, 'flv=') === 0) {
2202
                                    $source = substr($source, 4);
2203
                                    if (strpos($source, '&') > 0) {
2204
                                        $source = substr($source, 0, strpos($source, '&'));
2205
                                    }
2206
                                    if (strpos($source, '://') > 0) {
2207
                                        if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2208
                                            //we found the current portal url
2209
                                            $files_list[] = [$source, 'local', 'url'];
2210
                                        } else {
2211
                                            //we didn't find any trace of current portal
2212
                                            $files_list[] = [$source, 'remote', 'url'];
2213
                                        }
2214
                                    } else {
2215
                                        $files_list[] = [$source, 'local', 'abs'];
2216
                                    }
2217
                                    /* skipping anything else to avoid two entries
2218
                                    (while the others can have sub-files in their url, flv's can't)*/
2219
                                    continue;
2220
                                }
2221
                            }
2222
                            if (strpos($source, '://') > 0) {
2223
                                //cut at '?' in a URL with params
2224
                                if (strpos($source, '?') > 0) {
2225
                                    $second_part = substr($source, strpos($source, '?'));
2226
                                    if (strpos($second_part, '://') > 0) {
2227
                                        //if the second part of the url contains a url too, treat the second one before cutting
2228
                                        $pos1 = strpos($second_part, '=');
2229
                                        $pos2 = strpos($second_part, '&');
2230
                                        $second_part = substr($second_part, $pos1 + 1, $pos2 - ($pos1 + 1));
2231
                                        if (strpos($second_part, api_get_path(WEB_PATH)) !== false) {
2232
                                            //we found the current portal url
2233
                                            $files_list[] = [$second_part, 'local', 'url'];
2234
                                            $in_files_list[] = self::get_resources_from_source_html(
2235
                                                $second_part,
2236
                                                true,
2237
                                                TOOL_DOCUMENT,
2238
                                                $recursivity + 1
2239
                                            );
2240
                                            if (count($in_files_list) > 0) {
2241
                                                $files_list = array_merge($files_list, $in_files_list);
2242
                                            }
2243
                                        } else {
2244
                                            //we didn't find any trace of current portal
2245
                                            $files_list[] = [$second_part, 'remote', 'url'];
2246
                                        }
2247
                                    } elseif (strpos($second_part, '=') > 0) {
2248
                                        if (substr($second_part, 0, 1) === '/') {
2249
                                            //link starts with a /, making it absolute (relative to DocumentRoot)
2250
                                            $files_list[] = [$second_part, 'local', 'abs'];
2251
                                            $in_files_list[] = self::get_resources_from_source_html(
2252
                                                $second_part,
2253
                                                true,
2254
                                                TOOL_DOCUMENT,
2255
                                                $recursivity + 1
2256
                                            );
2257
                                            if (count($in_files_list) > 0) {
2258
                                                $files_list = array_merge($files_list, $in_files_list);
2259
                                            }
2260
                                        } elseif (strstr($second_part, '..') === 0) {
2261
                                            //link is relative but going back in the hierarchy
2262
                                            $files_list[] = [$second_part, 'local', 'rel'];
2263
                                            //$dir = api_get_path(SYS_CODE_PATH);//dirname($abs_path);
2264
                                            //$new_abs_path = realpath($dir.'/'.$second_part);
2265
                                            $dir = '';
2266
                                            if (!empty($abs_path)) {
2267
                                                $dir = dirname($abs_path).'/';
2268
                                            }
2269
                                            $new_abs_path = realpath($dir.$second_part);
2270
                                            $in_files_list[] = self::get_resources_from_source_html(
2271
                                                $new_abs_path,
2272
                                                true,
2273
                                                TOOL_DOCUMENT,
2274
                                                $recursivity + 1
2275
                                            );
2276
                                            if (count($in_files_list) > 0) {
2277
                                                $files_list = array_merge($files_list, $in_files_list);
2278
                                            }
2279
                                        } else {
2280
                                            //no starting '/', making it relative to current document's path
2281
                                            if (substr($second_part, 0, 2) == './') {
2282
                                                $second_part = substr($second_part, 2);
2283
                                            }
2284
                                            $files_list[] = [$second_part, 'local', 'rel'];
2285
                                            $dir = '';
2286
                                            if (!empty($abs_path)) {
2287
                                                $dir = dirname($abs_path).'/';
2288
                                            }
2289
                                            $new_abs_path = realpath($dir.$second_part);
2290
                                            $in_files_list[] = self::get_resources_from_source_html(
2291
                                                $new_abs_path,
2292
                                                true,
2293
                                                TOOL_DOCUMENT,
2294
                                                $recursivity + 1
2295
                                            );
2296
                                            if (count($in_files_list) > 0) {
2297
                                                $files_list = array_merge($files_list, $in_files_list);
2298
                                            }
2299
                                        }
2300
                                    }
2301
                                    //leave that second part behind now
2302
                                    $source = substr($source, 0, strpos($source, '?'));
2303
                                    if (strpos($source, '://') > 0) {
2304
                                        if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2305
                                            //we found the current portal url
2306
                                            $files_list[] = [$source, 'local', 'url'];
2307
                                            $in_files_list[] = self::get_resources_from_source_html(
2308
                                                $source,
2309
                                                true,
2310
                                                TOOL_DOCUMENT,
2311
                                                $recursivity + 1
2312
                                            );
2313
                                            if (count($in_files_list) > 0) {
2314
                                                $files_list = array_merge($files_list, $in_files_list);
2315
                                            }
2316
                                        } else {
2317
                                            //we didn't find any trace of current portal
2318
                                            $files_list[] = [$source, 'remote', 'url'];
2319
                                        }
2320
                                    } else {
2321
                                        //no protocol found, make link local
2322
                                        if (substr($source, 0, 1) === '/') {
2323
                                            //link starts with a /, making it absolute (relative to DocumentRoot)
2324
                                            $files_list[] = [$source, 'local', 'abs'];
2325
                                            $in_files_list[] = self::get_resources_from_source_html(
2326
                                                $source,
2327
                                                true,
2328
                                                TOOL_DOCUMENT,
2329
                                                $recursivity + 1
2330
                                            );
2331
                                            if (count($in_files_list) > 0) {
2332
                                                $files_list = array_merge($files_list, $in_files_list);
2333
                                            }
2334
                                        } elseif (strstr($source, '..') === 0) {
2335
                                            //link is relative but going back in the hierarchy
2336
                                            $files_list[] = [$source, 'local', 'rel'];
2337
                                            $dir = '';
2338
                                            if (!empty($abs_path)) {
2339
                                                $dir = dirname($abs_path).'/';
2340
                                            }
2341
                                            $new_abs_path = realpath($dir.$source);
2342
                                            $in_files_list[] = self::get_resources_from_source_html(
2343
                                                $new_abs_path,
2344
                                                true,
2345
                                                TOOL_DOCUMENT,
2346
                                                $recursivity + 1
2347
                                            );
2348
                                            if (count($in_files_list) > 0) {
2349
                                                $files_list = array_merge($files_list, $in_files_list);
2350
                                            }
2351
                                        } else {
2352
                                            //no starting '/', making it relative to current document's path
2353
                                            if (substr($source, 0, 2) == './') {
2354
                                                $source = substr($source, 2);
2355
                                            }
2356
                                            $files_list[] = [$source, 'local', 'rel'];
2357
                                            $dir = '';
2358
                                            if (!empty($abs_path)) {
2359
                                                $dir = dirname($abs_path).'/';
2360
                                            }
2361
                                            $new_abs_path = realpath($dir.$source);
2362
                                            $in_files_list[] = self::get_resources_from_source_html(
2363
                                                $new_abs_path,
2364
                                                true,
2365
                                                TOOL_DOCUMENT,
2366
                                                $recursivity + 1
2367
                                            );
2368
                                            if (count($in_files_list) > 0) {
2369
                                                $files_list = array_merge($files_list, $in_files_list);
2370
                                            }
2371
                                        }
2372
                                    }
2373
                                }
2374
                                //found some protocol there
2375
                                if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2376
                                    //we found the current portal url
2377
                                    $files_list[] = [$source, 'local', 'url'];
2378
                                    $in_files_list[] = self::get_resources_from_source_html(
2379
                                        $source,
2380
                                        true,
2381
                                        TOOL_DOCUMENT,
2382
                                        $recursivity + 1
2383
                                    );
2384
                                    if (count($in_files_list) > 0) {
2385
                                        $files_list = array_merge($files_list, $in_files_list);
2386
                                    }
2387
                                } else {
2388
                                    //we didn't find any trace of current portal
2389
                                    $files_list[] = [$source, 'remote', 'url'];
2390
                                }
2391
                            } else {
2392
                                //no protocol found, make link local
2393
                                if (substr($source, 0, 1) === '/') {
2394
                                    //link starts with a /, making it absolute (relative to DocumentRoot)
2395
                                    $files_list[] = [$source, 'local', 'abs'];
2396
                                    $in_files_list[] = self::get_resources_from_source_html(
2397
                                        $source,
2398
                                        true,
2399
                                        TOOL_DOCUMENT,
2400
                                        $recursivity + 1
2401
                                    );
2402
                                    if (count($in_files_list) > 0) {
2403
                                        $files_list = array_merge($files_list, $in_files_list);
2404
                                    }
2405
                                } elseif (strpos($source, '..') === 0) {
2406
                                    //link is relative but going back in the hierarchy
2407
                                    $files_list[] = [$source, 'local', 'rel'];
2408
                                    $dir = '';
2409
                                    if (!empty($abs_path)) {
2410
                                        $dir = dirname($abs_path).'/';
2411
                                    }
2412
                                    $new_abs_path = realpath($dir.$source);
2413
                                    $in_files_list[] = self::get_resources_from_source_html(
2414
                                        $new_abs_path,
2415
                                        true,
2416
                                        TOOL_DOCUMENT,
2417
                                        $recursivity + 1
2418
                                    );
2419
                                    if (count($in_files_list) > 0) {
2420
                                        $files_list = array_merge($files_list, $in_files_list);
2421
                                    }
2422
                                } else {
2423
                                    //no starting '/', making it relative to current document's path
2424
                                    if (substr($source, 0, 2) == './') {
2425
                                        $source = substr($source, 2);
2426
                                    }
2427
                                    $files_list[] = [$source, 'local', 'rel'];
2428
                                    $dir = '';
2429
                                    if (!empty($abs_path)) {
2430
                                        $dir = dirname($abs_path).'/';
2431
                                    }
2432
                                    $new_abs_path = realpath($dir.$source);
2433
                                    $in_files_list[] = self::get_resources_from_source_html(
2434
                                        $new_abs_path,
2435
                                        true,
2436
                                        TOOL_DOCUMENT,
2437
                                        $recursivity + 1
2438
                                    );
2439
                                    if (count($in_files_list) > 0) {
2440
                                        $files_list = array_merge($files_list, $in_files_list);
2441
                                    }
2442
                                }
2443
                            }
2444
                        }
2445
                    }
2446
                }
2447
                break;
2448
            default: //ignore
2449
                break;
2450
        }
2451
2452
        $checked_files_list = [];
2453
        $checked_array_list = [];
2454
2455
        if (count($files_list) > 0) {
2456
            foreach ($files_list as $idx => $file) {
2457
                if (!empty($file[0])) {
2458
                    if (!in_array($file[0], $checked_files_list)) {
2459
                        $checked_files_list[] = $files_list[$idx][0];
2460
                        $checked_array_list[] = $files_list[$idx];
2461
                    }
2462
                }
2463
            }
2464
        }
2465
2466
        return $checked_array_list;
2467
    }
2468
2469
    /**
2470
     * Parses the HTML attributes given as string.
2471
     *
2472
     * @param string HTML attribute string
2473
     * @param array List of attributes that we want to get back
2474
     * @param array
2475
     *
2476
     * @return array An associative array of attributes
2477
     *
2478
     * @author Based on a function from the HTML_Common2 PEAR module     *
2479
     */
2480
    public static function parse_HTML_attributes($attrString, $wanted = [], $explode_variables = [])
2481
    {
2482
        $attributes = [];
2483
        $regs = [];
2484
        $reduced = false;
2485
        if (count($wanted) > 0) {
2486
            $reduced = true;
2487
        }
2488
        try {
2489
            //Find all occurences of something that looks like a URL
2490
            // The structure of this regexp is:
2491
            // (find protocol) then
2492
            // (optionally find some kind of space 1 or more times) then
2493
            // find (either an equal sign or a bracket) followed by an optional space
2494
            // followed by some text without quotes (between quotes itself or not)
2495
            // then possible closing brackets if we were in the opening bracket case
2496
            // OR something like @import()
2497
            $res = preg_match_all(
2498
                '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]*))'.
2499
                // '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]|[^\x00-\x7F])*)' . -> seems to be taking too much
2500
                // '/(((([A-Za-z_:])([^\x00-\x7F])*)' . -> takes only last letter of parameter name
2501
                '([ \n\t\r]+)?('.
2502
                // '(=([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+))' . -> doesn't restrict close enough to the url itself
2503
                '(=([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+))'.
2504
                '|'.
2505
                // '(\(([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)\))' . -> doesn't restrict close enough to the url itself
2506
                '(\(([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+)\))'.
2507
                '))'.
2508
                '|'.
2509
                // '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))?/', -> takes a lot (like 100's of thousands of empty possibilities)
2510
                '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))/',
2511
                $attrString,
2512
                $regs
2513
            );
2514
        } catch (Exception $e) {
2515
            error_log('Caught exception: '.$e->getMessage(), 0);
2516
        }
2517
        if ($res) {
2518
            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...
2519
                $name = trim($regs[3][$i]);
2520
                $check = trim($regs[0][$i]);
2521
                $value = trim($regs[10][$i]);
2522
                if (empty($value) and !empty($regs[13][$i])) {
2523
                    $value = $regs[13][$i];
2524
                }
2525
                if (empty($name) && !empty($regs[16][$i])) {
2526
                    $name = '@import';
2527
                    $value = trim($regs[16][$i]);
2528
                }
2529
                if (!empty($name)) {
2530
                    if (!$reduced || in_array(strtolower($name), $wanted)) {
2531
                        if ($name == $check) {
2532
                            $attributes[strtolower($name)][] = strtolower($name);
2533
                        } else {
2534
                            if (!empty($value) && ($value[0] == '\'' || $value[0] == '"')) {
2535
                                $value = substr($value, 1, -1);
2536
                            }
2537
2538
                            if ($value == 'API.LMSGetValue(name') {
2539
                                $value = 'API.LMSGetValue(name)';
2540
                            }
2541
                            //Gets the xx.flv value from the string flashvars="width=320&height=240&autostart=false&file=xxx.flv&repeat=false"
2542
                            if (isset($explode_variables[$name])) {
2543
                                $value_modified = str_replace('&amp;', '&', $value);
2544
                                $value_array = explode('&', $value_modified);
2545
                                foreach ($value_array as $item) {
2546
                                    $itemParts = explode('=', $item);
2547
                                    $key = $itemParts[0];
2548
                                    $item_value = !empty($itemParts[1]) ? $itemParts[1] : '';
2549
                                    if ($key == $explode_variables[$name]) {
2550
                                        $attributes[strtolower($name)][] = $item_value;
2551
                                    }
2552
                                }
2553
                            }
2554
                            $attributes[strtolower($name)][] = $value;
2555
                        }
2556
                    }
2557
                }
2558
            }
2559
        }
2560
2561
        return $attributes;
2562
    }
2563
2564
    /**
2565
     * Replace urls inside content html from a copy course.
2566
     *
2567
     * @param string $content_html
2568
     * @param string $origin_course_code
2569
     * @param string $destination_course_directory
2570
     * @param string $origin_course_path_from_zip
2571
     * @param string $origin_course_info_path
2572
     *
2573
     * @return string new content html with replaced urls or return false if content is not a string
2574
     */
2575
    public static function replaceUrlWithNewCourseCode(
2576
        $content_html,
2577
        $origin_course_code,
2578
        $destination_course_directory,
2579
        $origin_course_path_from_zip = null,
2580
        $origin_course_info_path = null
2581
    ) {
2582
        if (empty($content_html)) {
2583
            return false;
2584
        }
2585
2586
        $orig_source_html = self::get_resources_from_source_html($content_html);
2587
        $orig_course_info = api_get_course_info($origin_course_code);
2588
2589
        // Course does not exist in the current DB probably this came from a zip file?
2590
        if (empty($orig_course_info)) {
2591
            if (!empty($origin_course_path_from_zip)) {
2592
                $orig_course_path = $origin_course_path_from_zip.'/';
2593
                $orig_course_info_path = $origin_course_info_path;
2594
            }
2595
        } else {
2596
            $orig_course_path = api_get_path(SYS_COURSE_PATH).$orig_course_info['path'].'/';
2597
            $orig_course_info_path = $orig_course_info['path'];
2598
        }
2599
2600
        $destination_course_code = CourseManager::getCourseCodeFromDirectory($destination_course_directory);
2601
        $destination_course_info = api_get_course_info($destination_course_code);
2602
        $dest_course_path = api_get_path(SYS_COURSE_PATH).$destination_course_directory.'/';
2603
        $dest_course_path_rel = api_get_path(REL_COURSE_PATH).$destination_course_directory.'/';
2604
2605
        $user_id = api_get_user_id();
2606
2607
        if (!empty($orig_source_html)) {
2608
            foreach ($orig_source_html as $source) {
2609
                // Get information about source url
2610
                $real_orig_url = $source[0]; // url
2611
                $scope_url = $source[1]; // scope (local, remote)
2612
                $type_url = $source[2]; // type (rel, abs, url)
2613
2614
                // Get path and query from origin url
2615
                $orig_parse_url = parse_url($real_orig_url);
2616
                $real_orig_path = isset($orig_parse_url['path']) ? $orig_parse_url['path'] : null;
2617
                $real_orig_query = isset($orig_parse_url['query']) ? $orig_parse_url['query'] : null;
2618
2619
                // Replace origin course code by destination course code from origin url query
2620
                $dest_url_query = '';
2621
2622
                if (!empty($real_orig_query)) {
2623
                    $dest_url_query = '?'.$real_orig_query;
2624
                    if (strpos($dest_url_query, $origin_course_code) !== false) {
2625
                        $dest_url_query = str_replace($origin_course_code, $destination_course_code, $dest_url_query);
2626
                    }
2627
                }
2628
2629
                if ($scope_url == 'local') {
2630
                    if ($type_url == 'abs' || $type_url == 'rel') {
2631
                        $document_file = strstr($real_orig_path, 'document');
2632
2633
                        if (strpos($real_orig_path, $document_file) !== false) {
2634
                            $origin_filepath = $orig_course_path.$document_file;
2635
                            $destination_filepath = $dest_course_path.$document_file;
2636
2637
                            // copy origin file inside destination course
2638
                            if (file_exists($origin_filepath)) {
2639
                                $filepath_dir = dirname($destination_filepath);
2640
2641
                                if (!is_dir($filepath_dir)) {
2642
                                    $perm = api_get_permissions_for_new_directories();
2643
                                    $result = @mkdir($filepath_dir, $perm, true);
2644
                                    if ($result) {
2645
                                        $filepath_to_add = str_replace(
2646
                                            [$dest_course_path, 'document'],
2647
                                            '',
2648
                                            $filepath_dir
2649
                                        );
2650
2651
                                        //Add to item properties to the new folder
2652
                                        $doc_id = add_document(
2653
                                            $destination_course_info,
2654
                                            $filepath_to_add,
2655
                                            'folder',
2656
                                            0,
2657
                                            basename($filepath_to_add)
2658
                                        );
2659
                                        api_item_property_update(
2660
                                            $destination_course_info,
2661
                                            TOOL_DOCUMENT,
2662
                                            $doc_id,
2663
                                            'FolderCreated',
2664
                                            $user_id,
2665
                                            null,
2666
                                            null,
2667
                                            null,
2668
                                            null
2669
                                        );
2670
                                    }
2671
                                }
2672
2673
                                if (!file_exists($destination_filepath)) {
2674
                                    $result = @copy($origin_filepath, $destination_filepath);
2675
                                    if ($result) {
2676
                                        $filepath_to_add = str_replace(
2677
                                            [$dest_course_path, 'document'],
2678
                                            '',
2679
                                            $destination_filepath
2680
                                        );
2681
                                        $size = filesize($destination_filepath);
2682
2683
                                        // Add to item properties to the file
2684
                                        $doc_id = add_document(
2685
                                            $destination_course_info,
2686
                                            $filepath_to_add,
2687
                                            'file',
2688
                                            $size,
2689
                                            basename($filepath_to_add)
2690
                                        );
2691
                                        api_item_property_update(
2692
                                            $destination_course_info,
2693
                                            TOOL_DOCUMENT,
2694
                                            $doc_id,
2695
                                            'FolderCreated',
2696
                                            $user_id,
2697
                                            null,
2698
                                            null,
2699
                                            null,
2700
                                            null
2701
                                        );
2702
                                    }
2703
                                }
2704
                            }
2705
2706
                            // Replace origin course path by destination course path.
2707
                            if (strpos($content_html, $real_orig_url) !== false) {
2708
                                $url_course_path = str_replace(
2709
                                    $orig_course_info_path.'/'.$document_file,
2710
                                    '',
2711
                                    $real_orig_path
2712
                                );
2713
                                // See BT#7780
2714
                                $destination_url = $dest_course_path_rel.$document_file.$dest_url_query;
2715
                                // If the course code doesn't exist in the path? what we do? Nothing! see BT#1985
2716
                                if (strpos($real_orig_path, $origin_course_code) === false) {
2717
                                    $url_course_path = $real_orig_path;
2718
                                    $destination_url = $real_orig_path;
2719
                                }
2720
                                $content_html = str_replace($real_orig_url, $destination_url, $content_html);
2721
                            }
2722
                        }
2723
2724
                        // replace origin course code by destination course code  from origin url
2725
                        if (strpos($real_orig_url, '?') === 0) {
2726
                            $dest_url = str_replace($origin_course_code, $destination_course_code, $real_orig_url);
2727
                            $content_html = str_replace($real_orig_url, $dest_url, $content_html);
2728
                        }
2729
                    }
2730
                }
2731
            }
2732
        }
2733
2734
        return $content_html;
2735
    }
2736
2737
    /**
2738
     * Export document to PDF.
2739
     *
2740
     * @param int    $document_id
2741
     * @param string $courseCode
2742
     * @param string $orientation
2743
     * @param bool   $showHeaderAndFooter
2744
     */
2745
    public static function export_to_pdf(
2746
        $document_id,
2747
        $courseCode,
2748
        $orientation = 'landscape',
2749
        $showHeaderAndFooter = true
2750
    ) {
2751
        $course_data = api_get_course_info($courseCode);
2752
        $document_data = self::get_document_data_by_id($document_id, $courseCode);
2753
        $file_path = api_get_path(SYS_COURSE_PATH).$course_data['path'].'/document'.$document_data['path'];
2754
        if ($orientation == 'landscape') {
2755
            $pageFormat = 'A4-L';
2756
            $pdfOrientation = 'L';
2757
        } else {
2758
            $pageFormat = 'A4';
2759
            $pdfOrientation = 'P';
2760
        }
2761
        $pdf = new PDF(
2762
            $pageFormat,
2763
            $pdfOrientation,
2764
            $showHeaderAndFooter ? [] : ['top' => 0, 'left' => 0, 'bottom' => 0, 'right' => 0]
2765
        );
2766
2767
        if (api_get_configuration_value('use_alternative_document_pdf_footer')) {
2768
            $view = new Template('', false, false, false, true, false, false);
2769
            $template = $view->get_template('export/alt_pdf_footer.tpl');
2770
2771
            $pdf->set_custom_footer([
2772
                'html' => $view->fetch($template),
2773
            ]);
2774
        }
2775
2776
        $pdf->html_to_pdf(
2777
            $file_path,
2778
            $document_data['title'],
2779
            $courseCode,
2780
            false,
2781
            $showHeaderAndFooter
2782
        );
2783
    }
2784
2785
    /**
2786
     * Uploads a document.
2787
     *
2788
     * @param array  $files                   the $_FILES variable
2789
     * @param string $path
2790
     * @param string $title
2791
     * @param string $comment
2792
     * @param int    $unzip                   unzip or not the file
2793
     * @param string $ifExists                overwrite, rename or warn (default)
2794
     * @param bool   $index_document          index document (search xapian module)
2795
     * @param bool   $show_output             print html messages
2796
     * @param string $fileKey
2797
     * @param bool   $treat_spaces_as_hyphens
2798
     *
2799
     * @return array|bool
2800
     */
2801
    public static function upload_document(
2802
        $files,
2803
        $path,
2804
        $title = '',
2805
        $comment = '',
2806
        $unzip = 0,
2807
        $ifExists = '',
2808
        $index_document = false,
2809
        $show_output = false,
2810
        $fileKey = 'file',
2811
        $treat_spaces_as_hyphens = true
2812
    ) {
2813
        $course_info = api_get_course_info();
2814
        $sessionId = api_get_session_id();
2815
        $course_dir = $course_info['path'].'/document';
2816
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
2817
        $base_work_dir = $sys_course_path.$course_dir;
2818
2819
        if (isset($files[$fileKey])) {
2820
            $uploadOk = process_uploaded_file($files[$fileKey], $show_output);
2821
            if ($uploadOk) {
2822
                $new_path = handle_uploaded_document(
2823
                    $course_info,
2824
                    $files[$fileKey],
2825
                    $base_work_dir,
2826
                    $path,
2827
                    api_get_user_id(),
2828
                    api_get_group_id(),
2829
                    null,
2830
                    $unzip,
2831
                    $ifExists,
2832
                    $show_output,
2833
                    false,
2834
                    null,
2835
                    $sessionId,
2836
                    $treat_spaces_as_hyphens
2837
                );
2838
2839
                // Showing message when sending zip files
2840
                if ($new_path === true && $unzip == 1) {
2841
                    if ($show_output) {
2842
                        echo Display::return_message(
2843
                            get_lang('UplUploadSucceeded').'<br />',
2844
                            'confirm',
2845
                            false
2846
                        );
2847
                    }
2848
2849
                    return [
2850
                        'title' => $files[$fileKey]['name'],
2851
                        'url' => '#',
2852
                    ];
2853
                }
2854
2855
                if ($new_path) {
2856
                    $documentId = self::get_document_id(
2857
                        $course_info,
2858
                        $new_path,
2859
                        $sessionId
2860
                    );
2861
2862
                    if (!empty($documentId)) {
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
                            $documentId,
2889
                            $course_info['code'],
2890
                            null,
2891
                            $_POST['language'],
2892
                            $_REQUEST,
2893
                            $ifExists
2894
                        );
2895
                    }
2896
2897
                    if (!empty($documentId) && is_numeric($documentId)) {
2898
                        $documentData = self::get_document_data_by_id(
2899
                            $documentId,
2900
                            $course_info['code'],
2901
                            false,
2902
                            $sessionId
2903
                        );
2904
2905
                        return $documentData;
2906
                    }
2907
                }
2908
            }
2909
        }
2910
2911
        return false;
2912
    }
2913
2914
    /**
2915
     * Obtains the text inside the file with the right parser.
2916
     */
2917
    public static function get_text_content($doc_path, $doc_mime)
2918
    {
2919
        // TODO: review w$ compatibility
2920
        // Use usual exec output lines array to store stdout instead of a temp file
2921
        // because we need to store it at RAM anyway before index on ChamiloIndexer object
2922
        $ret_val = null;
2923
        switch ($doc_mime) {
2924
            case 'text/plain':
2925
                $handle = fopen($doc_path, 'r');
2926
                $output = [fread($handle, filesize($doc_path))];
2927
                fclose($handle);
2928
                break;
2929
            case 'application/pdf':
2930
                exec("pdftotext $doc_path -", $output, $ret_val);
2931
                break;
2932
            case 'application/postscript':
2933
                $temp_file = tempnam(sys_get_temp_dir(), 'chamilo');
2934
                exec("ps2pdf $doc_path $temp_file", $output, $ret_val);
2935
                if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
2936
                    return false;
2937
                }
2938
                exec("pdftotext $temp_file -", $output, $ret_val);
2939
                unlink($temp_file);
2940
                break;
2941
            case 'application/msword':
2942
                exec("catdoc $doc_path", $output, $ret_val);
2943
                break;
2944
            case 'text/html':
2945
                exec("html2text $doc_path", $output, $ret_val);
2946
                break;
2947
            case 'text/rtf':
2948
                // Note: correct handling of code pages in unrtf
2949
                // on debian lenny unrtf v0.19.2 can not, but unrtf v0.20.5 can
2950
                exec("unrtf --text $doc_path", $output, $ret_val);
2951
                if ($ret_val == 127) { // command not found
2952
                    return false;
2953
                }
2954
                // Avoid index unrtf comments
2955
                if (is_array($output) && count($output) > 1) {
2956
                    $parsed_output = [];
2957
                    foreach ($output as &$line) {
2958
                        if (!preg_match('/^###/', $line, $matches)) {
2959
                            if (!empty($line)) {
2960
                                $parsed_output[] = $line;
2961
                            }
2962
                        }
2963
                    }
2964
                    $output = $parsed_output;
2965
                }
2966
                break;
2967
            case 'application/vnd.ms-powerpoint':
2968
                exec("catppt $doc_path", $output, $ret_val);
2969
                break;
2970
            case 'application/vnd.ms-excel':
2971
                exec("xls2csv -c\" \" $doc_path", $output, $ret_val);
2972
                break;
2973
        }
2974
2975
        $content = '';
2976
        if (!is_null($ret_val)) {
2977
            if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
2978
                return false;
2979
            }
2980
        }
2981
        if (isset($output)) {
2982
            foreach ($output as &$line) {
2983
                $content .= $line."\n";
2984
            }
2985
2986
            return $content;
2987
        } else {
2988
            return false;
2989
        }
2990
    }
2991
2992
    /**
2993
     * Calculates the total size of all documents in a course.
2994
     *
2995
     * @author Bert vanderkimpen
2996
     *
2997
     * @param int $course_id
2998
     * @param int $group_id   (to calculate group document space)
2999
     * @param int $session_id
3000
     *
3001
     * @return int total size
3002
     */
3003
    public static function documents_total_space($course_id = null, $group_id = null, $session_id = null)
3004
    {
3005
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
3006
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
3007
3008
        $session_id = (int) $session_id;
3009
        $group_id = (int) $group_id;
3010
        $course_id = (int) $course_id;
3011
3012
        if (!$course_id) {
3013
            $course_id = api_get_course_int_id();
3014
        }
3015
3016
        $group_condition = '';
3017
        if ($group_id) {
3018
            $group_condition = " AND props.to_group_id='".$group_id."' ";
3019
        }
3020
3021
        $session_condition = '';
3022
        if ($session_id) {
3023
            $session_condition = " AND props.session_id='".$session_id."' ";
3024
        }
3025
3026
        $sql = "SELECT SUM(size)
3027
                FROM $TABLE_ITEMPROPERTY AS props
3028
                INNER JOIN $TABLE_DOCUMENT AS docs
3029
                ON (docs.id = props.ref AND props.c_id = docs.c_id)
3030
                WHERE
3031
                    props.c_id = $course_id AND
3032
                    docs.c_id = $course_id AND
3033
                    props.tool = '".TOOL_DOCUMENT."' AND
3034
                    props.visibility <> 2
3035
                    $group_condition
3036
                    $session_condition
3037
                ";
3038
        $result = Database::query($sql);
3039
3040
        if ($result && Database::num_rows($result) != 0) {
3041
            $row = Database::fetch_row($result);
3042
3043
            return (int) $row[0];
3044
        } else {
3045
            return 0;
3046
        }
3047
    }
3048
3049
    /**
3050
     * Display the document quota in a simple way.
3051
     *
3052
     *  Here we count 1 Kilobyte = 1024 Bytes, 1 Megabyte = 1048576 Bytes
3053
     */
3054
    public static function displaySimpleQuota($course_quota, $already_consumed_space)
3055
    {
3056
        $course_quota_m = round($course_quota / 1048576);
3057
        $already_consumed_space_m = round($already_consumed_space / 1048576, 2);
3058
        $percentage = $already_consumed_space / $course_quota * 100;
3059
        $percentage = round($percentage, 1);
3060
        $message = get_lang('YouAreCurrentlyUsingXOfYourX');
3061
        $message = sprintf($message, $already_consumed_space_m, $percentage.'%', $course_quota_m.' ');
3062
3063
        return Display::div($message, ['id' => 'document_quota']);
3064
    }
3065
3066
    /**
3067
     * Checks if there is enough place to add a file on a directory
3068
     * on the base of a maximum directory size allowed.
3069
     *
3070
     * @author Bert Vanderkimpen
3071
     *
3072
     * @param int $file_size     size of the file in byte
3073
     * @param int $max_dir_space maximum size
3074
     *
3075
     * @return bool true if there is enough space, false otherwise
3076
     *
3077
     * @see enough_space() uses  documents_total_space() function
3078
     */
3079
    public static function enough_space($file_size, $max_dir_space)
3080
    {
3081
        if ($max_dir_space) {
3082
            $already_filled_space = self::documents_total_space();
3083
            if (($file_size + $already_filled_space) > $max_dir_space) {
3084
                return false;
3085
            }
3086
        }
3087
3088
        return true;
3089
    }
3090
3091
    /**
3092
     * @param array $params count, url, extension
3093
     *
3094
     * @return string
3095
     */
3096
    public static function generateAudioJavascript($params = [])
3097
    {
3098
        $js = '
3099
            $(\'audio.audio_preview\').mediaelementplayer({
3100
                features: [\'playpause\'],
3101
                audioWidth: 30,
3102
                audioHeight: 30,
3103
                success: function(mediaElement, originalNode, instance) {                
3104
                }
3105
            });';
3106
3107
        return $js;
3108
    }
3109
3110
    /**
3111
     * Shows a play icon next to the document title in the document list.
3112
     *
3113
     * @param string $documentWebPath
3114
     * @param array  $documentInfo
3115
     *
3116
     * @return string
3117
     */
3118
    public static function generateAudioPreview($documentWebPath, $documentInfo)
3119
    {
3120
        $filePath = $documentWebPath.$documentInfo['path'];
3121
        $extension = $documentInfo['file_extension'];
3122
        $html = '<span class="preview"> <audio class="audio_preview skip" src="'.$filePath.'" type="audio/'.$extension.'" > </audio></span>';
3123
3124
        return $html;
3125
    }
3126
3127
    /**
3128
     * @param string $file
3129
     * @param string $extension
3130
     *
3131
     * @return string
3132
     */
3133
    public static function generateVideoPreview($file, $extension)
3134
    {
3135
        $type = '';
3136
        /*if ($extension != 'flv') {
3137
3138
        }*/
3139
        //$type = "video/$extension";
3140
        //$fileInfo = parse_url($file);
3141
        //$type = self::file_get_mime_type(basename($fileInfo['path']));
3142
3143
        $html = '<video id="myvideo" controls>';
3144
        $html .= '<source src="'.$file.'" >';
3145
        $html .= '</video>';
3146
3147
        return $html;
3148
    }
3149
3150
    /**
3151
     * @param array  $course_info
3152
     * @param bool   $lp_id
3153
     * @param string $target
3154
     * @param int    $session_id
3155
     * @param bool   $add_move_button
3156
     * @param string $filter_by_folder
3157
     * @param string $overwrite_url
3158
     * @param bool   $showInvisibleFiles
3159
     * @param bool   $showOnlyFolders
3160
     * @param int    $folderId
3161
     *
3162
     * @return string
3163
     */
3164
    public static function get_document_preview(
3165
        $course_info,
3166
        $lp_id = false,
3167
        $target = '',
3168
        $session_id = 0,
3169
        $add_move_button = false,
3170
        $filter_by_folder = null,
3171
        $overwrite_url = '',
3172
        $showInvisibleFiles = false,
3173
        $showOnlyFolders = false,
3174
        $folderId = false
3175
    ) {
3176
        if (empty($course_info['real_id']) || empty($course_info['code']) || !is_array($course_info)) {
3177
            return '';
3178
        }
3179
3180
        $user_id = api_get_user_id();
3181
        $userInfo = api_get_user_info();
3182
3183
        $user_in_course = false;
3184
        if (api_is_platform_admin()) {
3185
            $user_in_course = true;
3186
        }
3187
3188
        if (!$user_in_course) {
3189
            if (CourseManager::is_course_teacher($user_id, $course_info['code'])) {
3190
                $user_in_course = true;
3191
            }
3192
        }
3193
3194
        // Condition for the session
3195
        $session_id = intval($session_id);
3196
3197
        if (!$user_in_course) {
3198
            if (empty($session_id)) {
3199
                if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code'])) {
3200
                    $user_in_course = true;
3201
                }
3202
                // Check if course is open then we can consider that the student is registered to the course
3203
                if (isset($course_info) && in_array($course_info['visibility'], [2, 3])) {
3204
                    $user_in_course = true;
3205
                }
3206
            } else {
3207
                $user_status = SessionManager::get_user_status_in_course_session(
3208
                    $user_id,
3209
                    $course_info['real_id'],
3210
                    $session_id
3211
                );
3212
                //is true if is an student, course session teacher or coach
3213
                if (in_array($user_status, ['0', '2', '6'])) {
3214
                    $user_in_course = true;
3215
                }
3216
            }
3217
        }
3218
3219
        $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
3220
        $tbl_item_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
3221
        $condition_session = " AND (last.session_id = '$session_id' OR last.session_id = '0' OR last.session_id IS NULL)";
3222
3223
        $add_folder_filter = null;
3224
        if (!empty($filter_by_folder)) {
3225
            $add_folder_filter = " AND docs.path LIKE '".Database::escape_string($filter_by_folder)."%'";
3226
        }
3227
3228
        // If we are in LP display hidden folder https://support.chamilo.org/issues/6679
3229
        $lp_visibility_condition = null;
3230
        if ($lp_id) {
3231
            // $lp_visibility_condition = " OR filetype='folder'";
3232
            if ($showInvisibleFiles) {
3233
                $lp_visibility_condition .= ' OR last.visibility = 0';
3234
            }
3235
        }
3236
3237
        $showOnlyFoldersCondition = null;
3238
        if ($showOnlyFolders) {
3239
            //$showOnlyFoldersCondition = " AND docs.filetype = 'folder' ";
3240
        }
3241
3242
        $folderCondition = " AND docs.path LIKE '/%' ";
3243
3244
        if (!api_is_allowed_to_edit()) {
3245
            $protectedFolders = self::getProtectedFolderFromStudent();
3246
            foreach ($protectedFolders as $folder) {
3247
                $folderCondition .= " AND docs.path NOT LIKE '$folder' ";
3248
            }
3249
        }
3250
3251
        $parentData = [];
3252
        if ($folderId !== false) {
3253
            $parentData = self::get_document_data_by_id(
3254
                $folderId,
3255
                $course_info['code'],
3256
                false,
3257
                $session_id
3258
            );
3259
            if (!empty($parentData)) {
3260
                $cleanedPath = $parentData['path'];
3261
                $num = substr_count($cleanedPath, '/');
3262
3263
                $notLikeCondition = '';
3264
                for ($i = 1; $i <= $num; $i++) {
3265
                    $repeat = str_repeat('/%', $i + 1);
3266
                    $notLikeCondition .= " AND docs.path NOT LIKE '".Database::escape_string($cleanedPath.$repeat)."' ";
3267
                }
3268
3269
                $folderId = (int) $folderId;
3270
                $folderCondition = " AND
3271
                    docs.id <> $folderId AND
3272
                    docs.path LIKE '".$cleanedPath."/%'
3273
                    $notLikeCondition
3274
                ";
3275
            } else {
3276
                $folderCondition = " AND docs.filetype = 'file' ";
3277
            }
3278
        }
3279
3280
        $levelCondition = null;
3281
        if ($folderId === false) {
3282
            $levelCondition = " AND docs.path NOT LIKE'/%/%'";
3283
        }
3284
3285
        $sql = "SELECT DISTINCT last.visibility, docs.*
3286
                FROM $tbl_item_prop AS last 
3287
                INNER JOIN $tbl_doc AS docs
3288
                ON (docs.id = last.ref AND docs.c_id = last.c_id)
3289
                WHERE
3290
                    docs.path NOT LIKE '%_DELETED_%' AND
3291
                    last.tool = '".TOOL_DOCUMENT."' $condition_session AND
3292
                    (last.visibility = '1' $lp_visibility_condition) AND
3293
                    last.visibility <> 2 AND
3294
                    docs.c_id = {$course_info['real_id']} AND
3295
                    last.c_id = {$course_info['real_id']}
3296
                    $showOnlyFoldersCondition
3297
                    $folderCondition
3298
                    $levelCondition
3299
                    $add_folder_filter
3300
                ORDER BY docs.filetype DESC, docs.title ASC";
3301
3302
        $res_doc = Database::query($sql);
3303
        $resources = Database::store_result($res_doc, 'ASSOC');
3304
3305
        $return = '';
3306
        if ($lp_id) {
3307
            if ($folderId === false) {
3308
                /*$return .= '<div class="lp_resource_element">';
3309
                $return .= Display::return_icon('new_doc.gif', '', [], ICON_SIZE_SMALL);
3310
                $return .= Display::url(
3311
                    get_lang('CreateTheDocument'),
3312
                    api_get_self().'?'.api_get_cidreq().'&action=add_item&type='.TOOL_DOCUMENT.'&lp_id='.$_SESSION['oLP']->lp_id
3313
                );
3314
                $return .= '</div>';*/
3315
            }
3316
        } else {
3317
            $return .= Display::div(
3318
                Display::url(
3319
                    Display::return_icon('close.png', get_lang('Close'), [], ICON_SIZE_SMALL),
3320
                    ' javascript:void(0);',
3321
                    ['id' => 'close_div_'.$course_info['real_id'].'_'.$session_id, 'class' => 'close_div']
3322
                ),
3323
                ['style' => 'position:absolute;right:10px']
3324
            );
3325
        }
3326
3327
        // If you want to debug it, I advise you to do "echo" on the eval statements.
3328
        $newResources = [];
3329
        if (!empty($resources) && $user_in_course) {
3330
            foreach ($resources as $resource) {
3331
                $is_visible = self::is_visible_by_id(
3332
                    $resource['id'],
3333
                    $course_info,
3334
                    $session_id,
3335
                    api_get_user_id()
3336
                );
3337
3338
                if ($showInvisibleFiles === false) {
3339
                    if (!$is_visible) {
3340
                        continue;
3341
                    }
3342
                }
3343
3344
                $newResources[] = $resource;
3345
            }
3346
        }
3347
3348
        $label = get_lang('Documents');
3349
3350
        $documents = [];
3351
        if ($folderId === false) {
3352
            $documents[$label] = [
3353
                'id' => 0,
3354
                'files' => $newResources,
3355
            ];
3356
        } else {
3357
            if (is_array($parentData)) {
3358
                $documents[$parentData['title']] = [
3359
                    'id' => (int) $folderId,
3360
                    'files' => $newResources,
3361
                ];
3362
            }
3363
        }
3364
3365
        $write_result = self::write_resources_tree(
3366
            $userInfo,
3367
            $course_info,
3368
            $session_id,
3369
            $documents,
3370
            $lp_id,
3371
            $target,
3372
            $add_move_button,
3373
            $overwrite_url,
3374
            $folderId
3375
        );
3376
3377
        $return .= $write_result;
3378
        if ($lp_id === false) {
3379
            $url = api_get_path(WEB_AJAX_PATH).
3380
                'lp.ajax.php?a=get_documents&url='.$overwrite_url.'&lp_id='.$lp_id.'&cidReq='.$course_info['code'];
3381
            $return .= "<script>
3382
            $('.doc_folder').click(function() {
3383
                var realId = this.id;
3384
                var my_id = this.id.split('_')[2];
3385
                var tempId = 'temp_'+my_id;
3386
                $('#res_'+my_id).show();
3387
                var tempDiv = $('#'+realId).find('#'+tempId);
3388
                if (tempDiv.length == 0) {
3389
                    $.ajax({
3390
                        async: false,
3391
                        type: 'GET',
3392
                        url:  '".$url."',
3393
                        data: 'folder_id='+my_id,
3394
                        success: function(data) {
3395
                            $('#'+realId).append('<div id='+tempId+'>'+data+'</div>');
3396
                        }
3397
                    });
3398
                }
3399
            });
3400
3401
            $('.close_div').click(function() {
3402
                var course_id = this.id.split('_')[2];
3403
                var session_id = this.id.split('_')[3];
3404
                $('#document_result_'+course_id+'_'+session_id).hide();
3405
                $('.lp_resource').remove();
3406
                $('.document_preview_container').html('');
3407
            });
3408
            </script>";
3409
        } else {
3410
            //For LPs
3411
            $url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?a=get_documents&lp_id='.$lp_id.'&'.api_get_cidreq();
3412
            $return .= "<script>
3413
3414
            function testResources(id, img) {
3415
                var numericId = id.split('_')[1];
3416
                var parentId = 'doc_id_'+numericId;
3417
                var tempId = 'temp_'+numericId;
3418
                var image = $('#'+img);
3419
3420
                if (image.hasClass('open')) {
3421
                    image.removeClass('open');
3422
                    image.attr('src', '".Display::returnIconPath('nolines_plus.gif')."');
3423
                    $('#'+id).show();
3424
                    $('#'+tempId).hide();
3425
                } else {
3426
                    image.addClass('open');
3427
                    image.attr('src', '".Display::returnIconPath('nolines_minus.gif')."');
3428
                    $('#'+id).hide();
3429
                    $('#'+tempId).show();
3430
                    var tempDiv = $('#'+parentId).find('#'+tempId);
3431
                    if (tempDiv.length == 0) {
3432
                        $.ajax({
3433
                            type: 'GET',
3434
                            async: false,
3435
                            url:  '".$url."',
3436
                            data: 'folder_id='+numericId,
3437
                            success: function(data) {
3438
                                tempDiv = $('#doc_id_'+numericId).append('<div id='+tempId+'>'+data+'</div>');
3439
                            }
3440
                        });
3441
                    }
3442
                }
3443
            }
3444
            </script>";
3445
        }
3446
3447
        if (!$user_in_course) {
3448
            $return = '';
3449
        }
3450
3451
        return $return;
3452
    }
3453
3454
    /**
3455
     * Generate and return an HTML list of resources based on a given array.
3456
     * This list is used to show the course creator a list of available resources to choose from
3457
     * when creating a learning path.
3458
     *
3459
     * @param array  $userInfo        current user info
3460
     * @param array  $course_info
3461
     * @param int    $session_id
3462
     * @param array  $documents
3463
     * @param bool   $lp_id
3464
     * @param string $target
3465
     * @param bool   $add_move_button
3466
     * @param string $overwrite_url
3467
     * @param int    $folderId
3468
     *
3469
     * @return string
3470
     */
3471
    public static function write_resources_tree(
3472
        $userInfo,
3473
        $course_info,
3474
        $session_id,
3475
        $documents,
3476
        $lp_id = false,
3477
        $target = '',
3478
        $add_move_button = false,
3479
        $overwrite_url = '',
3480
        $folderId = false
3481
    ) {
3482
        $return = '';
3483
        if (!empty($documents)) {
3484
            foreach ($documents as $key => $resource) {
3485
                if (isset($resource['id']) && is_int($resource['id'])) {
3486
                    $mainFolderResource = [
3487
                        'id' => $resource['id'],
3488
                        'title' => $key,
3489
                    ];
3490
3491
                    if ($folderId === false) {
3492
                        $return .= self::parseFolder($folderId, $mainFolderResource, $lp_id);
3493
                    }
3494
3495
                    if (isset($resource['files'])) {
3496
                        $return .= self::write_resources_tree(
3497
                            $userInfo,
3498
                            $course_info,
3499
                            $session_id,
3500
                            $resource['files'],
3501
                            $lp_id,
3502
                            $target,
3503
                            $add_move_button,
3504
                            $overwrite_url
3505
                        );
3506
                    }
3507
                    $return .= '</div>';
3508
                    $return .= '</ul>';
3509
                } else {
3510
                    if ($resource['filetype'] === 'folder') {
3511
                        $return .= self::parseFolder($folderId, $resource, $lp_id);
3512
                    } else {
3513
                        $return .= self::parseFile(
3514
                            $userInfo,
3515
                            $course_info,
3516
                            $session_id,
3517
                            $resource,
3518
                            $lp_id,
3519
                            $add_move_button,
3520
                            $target,
3521
                            $overwrite_url
3522
                        );
3523
                    }
3524
                }
3525
            }
3526
        }
3527
3528
        return $return;
3529
    }
3530
3531
    /**
3532
     * @param int    $doc_id
3533
     * @param string $course_code
3534
     * @param int    $session_id
3535
     * @param int    $user_id
3536
     * @param int    $groupId     iid
3537
     *
3538
     * @return bool
3539
     */
3540
    public static function check_visibility_tree(
3541
        $doc_id,
3542
        $course_code,
3543
        $session_id,
3544
        $user_id,
3545
        $groupId = 0
3546
    ) {
3547
        $document_data = self::get_document_data_by_id(
3548
            $doc_id,
3549
            $course_code,
3550
            null,
3551
            $session_id
3552
        );
3553
        if ($session_id != 0 && !$document_data) {
3554
            $document_data = self::get_document_data_by_id(
3555
                $doc_id,
3556
                $course_code,
3557
                null,
3558
                0
3559
            );
3560
        }
3561
3562
        if (!empty($document_data)) {
3563
            // If admin or course teacher, allow anyway
3564
            if (api_is_platform_admin() || CourseManager::is_course_teacher($user_id, $course_code)) {
3565
                return true;
3566
            }
3567
            $course_info = api_get_course_info($course_code);
3568
            if ($document_data['parent_id'] == false || empty($document_data['parent_id'])) {
3569
                if (!empty($groupId)) {
3570
                    return true;
3571
                }
3572
                $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
3573
3574
                return $visible;
3575
            } else {
3576
                $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
3577
3578
                if (!$visible) {
3579
                    return false;
3580
                } else {
3581
                    return self::check_visibility_tree(
3582
                        $document_data['parent_id'],
3583
                        $course_code,
3584
                        $session_id,
3585
                        $user_id,
3586
                        $groupId
3587
                    );
3588
                }
3589
            }
3590
        } else {
3591
            return false;
3592
        }
3593
    }
3594
3595
    /**
3596
     * Index a given document.
3597
     *
3598
     * @param   int     Document ID inside its corresponding course
3599
     * @param   string  Course code
3600
     * @param   int     Session ID (not used yet)
3601
     * @param   string  Language of document's content (defaults to course language)
3602
     * @param   array   Array of specific fields (['code'=>'value',...])
3603
     * @param   string  What to do if the file already exists (default or overwrite)
3604
     * @param   bool    When set to true, this runs the indexer without actually saving anything to any database
3605
     *
3606
     * @return bool Returns true on presumed success, false on failure
3607
     */
3608
    public static function index_document(
3609
        $docid,
3610
        $course_code,
3611
        $session_id = 0,
3612
        $lang = 'english',
3613
        $specific_fields_values = [],
3614
        $if_exists = '',
3615
        $simulation = false
3616
    ) {
3617
        if (api_get_setting('search_enabled') !== 'true') {
3618
            return false;
3619
        }
3620
        if (empty($docid) or $docid != intval($docid)) {
3621
            return false;
3622
        }
3623
        if (empty($session_id)) {
3624
            $session_id = api_get_session_id();
3625
        }
3626
        $course_info = api_get_course_info($course_code);
3627
        $course_dir = $course_info['path'].'/document';
3628
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
3629
        $base_work_dir = $sys_course_path.$course_dir;
3630
3631
        $course_id = $course_info['real_id'];
3632
        $table_document = Database::get_course_table(TABLE_DOCUMENT);
3633
3634
        $qry = "SELECT path, title FROM $table_document WHERE c_id = $course_id AND id = '$docid' LIMIT 1";
3635
        $result = Database::query($qry);
3636
        if (Database::num_rows($result) == 1) {
3637
            $row = Database::fetch_array($result);
3638
            $doc_path = api_get_path(SYS_COURSE_PATH).$course_dir.$row['path'];
3639
            //TODO: mime_content_type is deprecated, fileinfo php extension is enabled by default as of PHP 5.3.0
3640
            // now versions of PHP on Debian testing(5.2.6-5) and Ubuntu(5.2.6-2ubuntu) are lower, so wait for a while
3641
            $doc_mime = mime_content_type($doc_path);
3642
            $allowed_mime_types = self::file_get_mime_type(true);
3643
3644
            // mime_content_type does not detect correctly some formats that
3645
            // are going to be supported for index, so an extensions array is used for the moment
3646
            if (empty($doc_mime)) {
3647
                $allowed_extensions = [
3648
                    'doc',
3649
                    'docx',
3650
                    'ppt',
3651
                    'pptx',
3652
                    'pps',
3653
                    'ppsx',
3654
                    'xls',
3655
                    'xlsx',
3656
                    'odt',
3657
                    'odp',
3658
                    'ods',
3659
                    'pdf',
3660
                    'txt',
3661
                    'rtf',
3662
                    'msg',
3663
                    'csv',
3664
                    'html',
3665
                    'htm',
3666
                ];
3667
                $extensions = preg_split("/[\/\\.]/", $doc_path);
3668
                $doc_ext = strtolower($extensions[count($extensions) - 1]);
3669
                if (in_array($doc_ext, $allowed_extensions)) {
3670
                    switch ($doc_ext) {
3671
                        case 'ppt':
3672
                        case 'pps':
3673
                            $doc_mime = 'application/vnd.ms-powerpoint';
3674
                            break;
3675
                        case 'xls':
3676
                            $doc_mime = 'application/vnd.ms-excel';
3677
                            break;
3678
                    }
3679
                }
3680
            }
3681
3682
            //@todo move this nightmare in a search controller or something like that!!! J.M
3683
3684
            if (in_array($doc_mime, $allowed_mime_types)) {
3685
                $file_title = $row['title'];
3686
                $file_content = self::get_text_content($doc_path, $doc_mime);
3687
                $course_code = Database::escape_string($course_code);
3688
                $ic_slide = new IndexableChunk();
3689
                $ic_slide->addValue('title', $file_title);
3690
                $ic_slide->addCourseId($course_code);
3691
                $ic_slide->addToolId(TOOL_DOCUMENT);
3692
                $xapian_data = [
3693
                    SE_COURSE_ID => $course_code,
3694
                    SE_TOOL_ID => TOOL_DOCUMENT,
3695
                    SE_DATA => ['doc_id' => $docid],
3696
                    SE_USER => api_get_user_id(),
3697
                ];
3698
3699
                $ic_slide->xapian_data = serialize($xapian_data);
3700
                $di = new ChamiloIndexer();
3701
                $return = $di->connectDb(null, null, $lang);
3702
3703
                require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
3704
                $specific_fields = get_specific_field_list();
3705
3706
                // process different depending on what to do if file exists
3707
                /**
3708
                 * @TODO Find a way to really verify if the file had been
3709
                 * overwriten. Now all work is done at
3710
                 * handle_uploaded_document() and it's difficult to verify it
3711
                 */
3712
                if (!empty($if_exists) && $if_exists == 'overwrite') {
3713
                    // Overwrite the file on search engine
3714
                    // Actually, it consists on a delete of terms from db,
3715
                    // insert new ones, create a new search engine document,
3716
                    // and remove the old one
3717
                    // Get search_did
3718
                    $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3719
                    $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
3720
                    $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid);
3721
3722
                    $res = Database::query($sql);
3723
3724
                    if (Database::num_rows($res) > 0) {
3725
                        $se_ref = Database::fetch_array($res);
3726
                        if (!$simulation) {
3727
                            $di->remove_document($se_ref['search_did']);
3728
                        }
3729
                        $all_specific_terms = '';
3730
                        foreach ($specific_fields as $specific_field) {
3731
                            if (!$simulation) {
3732
                                delete_all_specific_field_value($course_code, $specific_field['id'], TOOL_DOCUMENT, $docid);
3733
                            }
3734
                            // Update search engine
3735
                            if (isset($specific_fields_values[$specific_field['code']])) {
3736
                                $sterms = trim($specific_fields_values[$specific_field['code']]);
3737
                            } else { //if the specific field is not defined, force an empty one
3738
                                $sterms = '';
3739
                            }
3740
                            $all_specific_terms .= ' '.$sterms;
3741
                            $sterms = explode(',', $sterms);
3742
                            foreach ($sterms as $sterm) {
3743
                                $sterm = trim($sterm);
3744
                                if (!empty($sterm)) {
3745
                                    $ic_slide->addTerm($sterm, $specific_field['code']);
3746
                                    // updated the last param here from $value to $sterm without being sure - see commit15464
3747
                                    if (!$simulation) {
3748
                                        add_specific_field_value(
3749
                                            $specific_field['id'],
3750
                                            $course_code,
3751
                                            TOOL_DOCUMENT,
3752
                                            $docid,
3753
                                            $sterm
3754
                                        );
3755
                                    }
3756
                                }
3757
                            }
3758
                        }
3759
                        // Add terms also to content to make terms findable by probabilistic search
3760
                        $file_content = $all_specific_terms.' '.$file_content;
3761
3762
                        if (!$simulation) {
3763
                            $ic_slide->addValue('content', $file_content);
3764
                            $di->addChunk($ic_slide);
3765
                            // Index and return a new search engine document id
3766
                            $did = $di->index();
3767
3768
                            if ($did) {
3769
                                // update the search_did on db
3770
                                $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3771
                                $sql = 'UPDATE %s SET search_did=%d WHERE id=%d LIMIT 1';
3772
                                $sql = sprintf($sql, $tbl_se_ref, (int) $did, (int) $se_ref['id']);
3773
                                Database::query($sql);
3774
                            }
3775
                        }
3776
                    }
3777
                } else {
3778
                    // Add all terms
3779
                    $all_specific_terms = '';
3780
                    foreach ($specific_fields as $specific_field) {
3781
                        if (isset($specific_fields_values[$specific_field['code']])) {
3782
                            $sterms = trim($specific_fields_values[$specific_field['code']]);
3783
                        } else { //if the specific field is not defined, force an empty one
3784
                            $sterms = '';
3785
                        }
3786
                        $all_specific_terms .= ' '.$sterms;
3787
                        if (!empty($sterms)) {
3788
                            $sterms = explode(',', $sterms);
3789
                            foreach ($sterms as $sterm) {
3790
                                if (!$simulation) {
3791
                                    $ic_slide->addTerm(trim($sterm), $specific_field['code']);
3792
                                    add_specific_field_value(
3793
                                        $specific_field['id'],
3794
                                        $course_code,
3795
                                        TOOL_DOCUMENT,
3796
                                        $docid,
3797
                                        $sterm
3798
                                    );
3799
                                }
3800
                            }
3801
                        }
3802
                    }
3803
                    // Add terms also to content to make terms findable by probabilistic search
3804
                    $file_content = $all_specific_terms.' '.$file_content;
3805
                    if (!$simulation) {
3806
                        $ic_slide->addValue('content', $file_content);
3807
                        $di->addChunk($ic_slide);
3808
                        // Index and return search engine document id
3809
                        $did = $di->index();
3810
                        if ($did) {
3811
                            // Save it to db
3812
                            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3813
                            $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
3814
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
3815
                            $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid, $did);
3816
                            Database::query($sql);
3817
                        } else {
3818
                            return false;
3819
                        }
3820
                    }
3821
                }
3822
            } else {
3823
                return false;
3824
            }
3825
        }
3826
3827
        return true;
3828
    }
3829
3830
    /**
3831
     * @return array
3832
     */
3833
    public static function get_web_odf_extension_list()
3834
    {
3835
        return ['ods', 'odt', 'odp'];
3836
    }
3837
3838
    /**
3839
     * Set of extension allowed to use Jodconverter.
3840
     *
3841
     * @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...
3842
     *              'to'
3843
     *              'all'
3844
     * @param $format   'text'
3845
     *                  'spreadsheet'
3846
     *                  'presentation'
3847
     *                  'drawing'
3848
     *                  'all'
3849
     *
3850
     * @return array
3851
     */
3852
    public static function getJodconverterExtensionList($mode, $format)
3853
    {
3854
        $extensionList = [];
3855
        $extensionListFromText = [
3856
            'odt',
3857
            'sxw',
3858
            'rtf',
3859
            'doc',
3860
            'docx',
3861
            'wpd',
3862
            'txt',
3863
        ];
3864
        $extensionListToText = [
3865
            'pdf',
3866
            'odt',
3867
            'sxw',
3868
            'rtf',
3869
            'doc',
3870
            'docx',
3871
            'txt',
3872
        ];
3873
        $extensionListFromSpreadsheet = [
3874
            'ods',
3875
            'sxc',
3876
            'xls',
3877
            'xlsx',
3878
            'csv',
3879
            'tsv',
3880
        ];
3881
        $extensionListToSpreadsheet = [
3882
            'pdf',
3883
            'ods',
3884
            'sxc',
3885
            'xls',
3886
            'xlsx',
3887
            'csv',
3888
            'tsv',
3889
        ];
3890
        $extensionListFromPresentation = [
3891
            'odp',
3892
            'sxi',
3893
            'ppt',
3894
            'pptx',
3895
        ];
3896
        $extensionListToPresentation = [
3897
            'pdf',
3898
            'swf',
3899
            'odp',
3900
            'sxi',
3901
            'ppt',
3902
            'pptx',
3903
        ];
3904
        $extensionListFromDrawing = ['odg'];
3905
        $extensionListToDrawing = ['svg', 'swf'];
3906
3907
        if ($mode === 'from') {
3908
            if ($format === 'text') {
3909
                $extensionList = array_merge($extensionList, $extensionListFromText);
3910
            } elseif ($format === 'spreadsheet') {
3911
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3912
            } elseif ($format === 'presentation') {
3913
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3914
            } elseif ($format === 'drawing') {
3915
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3916
            } elseif ($format === 'all') {
3917
                $extensionList = array_merge($extensionList, $extensionListFromText);
3918
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3919
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3920
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3921
            }
3922
        } elseif ($mode === 'to') {
3923
            if ($format === 'text') {
3924
                $extensionList = array_merge($extensionList, $extensionListToText);
3925
            } elseif ($format === 'spreadsheet') {
3926
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3927
            } elseif ($format === 'presentation') {
3928
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3929
            } elseif ($format === 'drawing') {
3930
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3931
            } elseif ($format === 'all') {
3932
                $extensionList = array_merge($extensionList, $extensionListToText);
3933
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3934
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3935
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3936
            }
3937
        } elseif ($mode === 'all') {
3938
            if ($format === 'text') {
3939
                $extensionList = array_merge($extensionList, $extensionListFromText);
3940
                $extensionList = array_merge($extensionList, $extensionListToText);
3941
            } elseif ($format === 'spreadsheet') {
3942
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3943
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3944
            } elseif ($format === 'presentation') {
3945
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3946
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3947
            } elseif ($format === 'drawing') {
3948
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3949
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3950
            } elseif ($format === 'all') {
3951
                $extensionList = array_merge($extensionList, $extensionListFromText);
3952
                $extensionList = array_merge($extensionList, $extensionListToText);
3953
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3954
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3955
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3956
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3957
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3958
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3959
            }
3960
        }
3961
3962
        return $extensionList;
3963
    }
3964
3965
    /**
3966
     * Get Format type list by extension and mode.
3967
     *
3968
     * @param string $mode Mode to search format type list
3969
     *
3970
     * @example 'from'
3971
     * @example 'to'
3972
     *
3973
     * @param string $extension file extension to check file type
3974
     *
3975
     * @return array
3976
     */
3977
    public static function getFormatTypeListConvertor($mode = 'from', $extension)
3978
    {
3979
        $formatTypesList = [];
3980
        $formatTypes = ['text', 'spreadsheet', 'presentation', 'drawing'];
3981
        foreach ($formatTypes as $formatType) {
3982
            if (in_array($extension, self::getJodconverterExtensionList($mode, $formatType))) {
3983
                $formatTypesList[] = $formatType;
3984
            }
3985
        }
3986
3987
        return $formatTypesList;
3988
    }
3989
3990
    /**
3991
     * @param string $path
3992
     * @param bool   $is_certificate_mode
3993
     *
3994
     * @return bool
3995
     */
3996
    public static function is_folder_to_avoid($path, $is_certificate_mode = false)
3997
    {
3998
        $foldersToAvoid = [
3999
            '/HotPotatoes_files',
4000
            '/certificates',
4001
        ];
4002
        $systemFolder = api_get_course_setting('show_system_folders');
4003
4004
        if ($systemFolder == 1) {
4005
            $foldersToAvoid = [];
4006
        }
4007
4008
        if (basename($path) == 'css') {
4009
            return true;
4010
        }
4011
4012
        if ($is_certificate_mode == false) {
4013
            //Certificate results
4014
            if (strstr($path, 'certificates')) {
4015
                return true;
4016
            }
4017
        }
4018
4019
        // Admin setting for Hide/Show the folders of all users
4020
        if (api_get_setting('show_users_folders') == 'false') {
4021
            $foldersToAvoid[] = '/shared_folder';
4022
4023
            if (strstr($path, 'shared_folder_session_')) {
4024
                return true;
4025
            }
4026
        }
4027
4028
        // Admin setting for Hide/Show Default folders to all users
4029
        if (api_get_setting('show_default_folders') == 'false') {
4030
            $foldersToAvoid[] = '/images';
4031
            $foldersToAvoid[] = '/flash';
4032
            $foldersToAvoid[] = '/audio';
4033
            $foldersToAvoid[] = '/video';
4034
        }
4035
4036
        // Admin setting for Hide/Show chat history folder
4037
        if (api_get_setting('show_chat_folder') == 'false') {
4038
            $foldersToAvoid[] = '/chat_files';
4039
        }
4040
4041
        if (is_array($foldersToAvoid)) {
4042
            return in_array($path, $foldersToAvoid);
4043
        } else {
4044
            return false;
4045
        }
4046
    }
4047
4048
    /**
4049
     * @return array
4050
     */
4051
    public static function get_system_folders()
4052
    {
4053
        return [
4054
            '/certificates',
4055
            '/HotPotatoes_files',
4056
            '/chat_files',
4057
            '/images',
4058
            '/flash',
4059
            '/audio',
4060
            '/video',
4061
            '/shared_folder',
4062
            '/learning_path',
4063
        ];
4064
    }
4065
4066
    /**
4067
     * @return array
4068
     */
4069
    public static function getProtectedFolderFromStudent()
4070
    {
4071
        return [
4072
            '/certificates',
4073
            '/HotPotatoes_files',
4074
            '/chat_files',
4075
            '/shared_folder',
4076
            '/learning_path',
4077
        ];
4078
    }
4079
4080
    /**
4081
     * @param string $courseCode
4082
     *
4083
     * @return string 'visible' or 'invisible' string
4084
     */
4085
    public static function getDocumentDefaultVisibility($courseCode)
4086
    {
4087
        $settings = api_get_setting('tool_visible_by_default_at_creation');
4088
        $defaultVisibility = 'visible';
4089
4090
        if (isset($settings['documents'])) {
4091
            $portalDefaultVisibility = 'invisible';
4092
            if ($settings['documents'] == 'true') {
4093
                $portalDefaultVisibility = 'visible';
4094
            }
4095
4096
            $defaultVisibility = $portalDefaultVisibility;
4097
        }
4098
4099
        if (api_get_setting('documents_default_visibility_defined_in_course') == 'true') {
4100
            $courseVisibility = api_get_course_setting('documents_default_visibility', $courseCode);
4101
            if (!empty($courseVisibility) && in_array($courseVisibility, ['visible', 'invisible'])) {
4102
                $defaultVisibility = $courseVisibility;
4103
            }
4104
        }
4105
4106
        return $defaultVisibility;
4107
    }
4108
4109
    /**
4110
     * @param array  $courseInfo
4111
     * @param int    $id         doc id
4112
     * @param string $visibility visible/invisible
4113
     * @param int    $userId
4114
     */
4115
    public static function updateVisibilityFromAllSessions($courseInfo, $id, $visibility, $userId)
4116
    {
4117
        $sessionList = SessionManager::get_session_by_course($courseInfo['real_id']);
4118
4119
        if (!empty($sessionList)) {
4120
            foreach ($sessionList as $session) {
4121
                $sessionId = $session['id'];
4122
                api_item_property_update(
4123
                    $courseInfo,
4124
                    TOOL_DOCUMENT,
4125
                    $id,
4126
                    $visibility,
4127
                    $userId,
4128
                    null,
4129
                    null,
4130
                    null,
4131
                    null,
4132
                    $sessionId
4133
                );
4134
            }
4135
        }
4136
    }
4137
4138
    /**
4139
     * @param string $file
4140
     *
4141
     * @return string
4142
     */
4143
    public static function readNanogongFile($file)
4144
    {
4145
        $nanoGongJarFile = api_get_path(WEB_LIBRARY_PATH).'nanogong/nanogong.jar';
4146
        $html = '<applet id="applet" archive="'.$nanoGongJarFile.'" code="gong.NanoGong" width="160" height="95">';
4147
        $html .= '<param name="SoundFileURL" value="'.$file.'" />';
4148
        $html .= '<param name="ShowSaveButton" value="false" />';
4149
        $html .= '<param name="ShowTime" value="true" />';
4150
        $html .= '<param name="ShowRecordButton" value="false" />';
4151
        $html .= '</applet>';
4152
4153
        return $html;
4154
    }
4155
4156
    /**
4157
     * @param string $filePath
4158
     * @param string $path
4159
     * @param array  $courseInfo
4160
     * @param int    $sessionId
4161
     * @param string $whatIfFileExists overwrite|rename
4162
     * @param int    $userId
4163
     * @param int    $groupId
4164
     * @param int    $toUserId
4165
     * @param string $comment
4166
     *
4167
     * @return bool|path
4168
     */
4169
    public static function addFileToDocumentTool(
4170
        $filePath,
4171
        $path,
4172
        $courseInfo,
4173
        $sessionId,
4174
        $userId,
4175
        $whatIfFileExists = 'overwrite',
4176
        $groupId = null,
4177
        $toUserId = null,
4178
        $comment = null
4179
    ) {
4180
        if (!file_exists($filePath)) {
4181
            return false;
4182
        }
4183
4184
        $fileInfo = pathinfo($filePath);
4185
4186
        $file = [
4187
            'name' => $fileInfo['basename'],
4188
            'tmp_name' => $filePath,
4189
            'size' => filesize($filePath),
4190
            'from_file' => true,
4191
        ];
4192
4193
        $course_dir = $courseInfo['path'].'/document';
4194
        $baseWorkDir = api_get_path(SYS_COURSE_PATH).$course_dir;
4195
4196
        $filePath = handle_uploaded_document(
4197
            $courseInfo,
4198
            $file,
4199
            $baseWorkDir,
4200
            $path,
4201
            $userId,
4202
            $groupId,
4203
            $toUserId,
4204
            false,
4205
            $whatIfFileExists,
4206
            false,
4207
            false,
4208
            $comment,
4209
            $sessionId
4210
        );
4211
4212
        if ($filePath) {
4213
            return self::get_document_id(
4214
                $courseInfo,
4215
                $filePath,
4216
                $sessionId
4217
            );
4218
        }
4219
4220
        return false;
4221
    }
4222
4223
    /**
4224
     * Converts wav to mp3 file.
4225
     * Requires the ffmpeg lib. In ubuntu: sudo apt-get install ffmpeg.
4226
     *
4227
     * @param string $wavFile
4228
     * @param bool   $removeWavFileIfSuccess
4229
     *
4230
     * @return bool
4231
     */
4232
    public static function convertWavToMp3($wavFile, $removeWavFileIfSuccess = false)
4233
    {
4234
        if (file_exists($wavFile)) {
4235
            try {
4236
                $ffmpeg = \FFMpeg\FFMpeg::create();
4237
                $video = $ffmpeg->open($wavFile);
4238
4239
                $mp3File = str_replace('wav', 'mp3', $wavFile);
4240
                $result = $video->save(new FFMpeg\Format\Audio\Mp3(), $mp3File);
4241
                if ($result && $removeWavFileIfSuccess) {
4242
                    unlink($wavFile);
4243
                }
4244
4245
                if (file_exists($mp3File)) {
4246
                    return $mp3File;
4247
                }
4248
            } catch (Exception $e) {
4249
                error_log($e->getMessage());
4250
                error_log($e->getPrevious()->getMessage());
4251
            }
4252
        }
4253
4254
        return false;
4255
    }
4256
4257
    /**
4258
     * @param string $documentData     wav document information
4259
     * @param array  $courseInfo
4260
     * @param int    $sessionId
4261
     * @param int    $userId           user that adds the document
4262
     * @param string $whatIfFileExists
4263
     * @param bool   $deleteWavFile
4264
     *
4265
     * @return bool
4266
     */
4267
    public static function addAndConvertWavToMp3(
4268
        $documentData,
4269
        $courseInfo,
4270
        $sessionId,
4271
        $userId,
4272
        $whatIfFileExists = 'overwrite',
4273
        $deleteWavFile = false
4274
    ) {
4275
        if (empty($documentData)) {
4276
            return false;
4277
        }
4278
4279
        if (isset($documentData['absolute_path']) &&
4280
            file_exists($documentData['absolute_path'])
4281
        ) {
4282
            $mp3FilePath = self::convertWavToMp3($documentData['absolute_path']);
4283
            error_log($mp3FilePath);
4284
4285
            if (!empty($mp3FilePath) && file_exists($mp3FilePath)) {
4286
                $documentId = self::addFileToDocumentTool(
4287
                    $mp3FilePath,
4288
                    dirname($documentData['path']),
4289
                    $courseInfo,
4290
                    $sessionId,
4291
                    $userId,
4292
                    $whatIfFileExists,
4293
                    null,
4294
                    null,
4295
                    $documentData['comment']
4296
                );
4297
4298
                if (!empty($documentId)) {
4299
                    if ($deleteWavFile) {
4300
                        $coursePath = $courseInfo['directory'].'/document';
4301
                        $documentPath = api_get_path(SYS_COURSE_PATH).$coursePath;
4302
                        self::delete_document(
4303
                            $courseInfo,
4304
                            null,
4305
                            $documentPath,
4306
                            $sessionId,
4307
                            $documentData['id']
4308
                        );
4309
                    }
4310
4311
                    return $documentId;
4312
                }
4313
            }
4314
        }
4315
4316
        return false;
4317
    }
4318
4319
    /**
4320
     * Sets.
4321
     *
4322
     * @param string $file         ($document_data['path'])
4323
     * @param string $file_url_sys
4324
     *
4325
     * @return string
4326
     */
4327
    public static function generateAudioTempFile($file, $file_url_sys)
4328
    {
4329
        //make temp audio
4330
        $temp_folder = api_get_path(SYS_ARCHIVE_PATH).'temp/audio';
4331
        if (!file_exists($temp_folder)) {
4332
            @mkdir($temp_folder, api_get_permissions_for_new_directories(), true);
4333
        }
4334
4335
        //make htaccess with allow from all, and file index.html into temp/audio
4336
        $htaccess = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess';
4337
        if (!file_exists($htaccess)) {
4338
            $htaccess_content = "order deny,allow\r\nallow from all\r\nOptions -Indexes";
4339
            $fp = @fopen(api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess', 'w');
4340
            if ($fp) {
4341
                fwrite($fp, $htaccess_content);
4342
                fclose($fp);
4343
            }
4344
        }
4345
4346
        //encript temp name file
4347
        $name_crip = sha1(uniqid()); //encript
4348
        $findext = explode(".", $file);
4349
        $extension = $findext[count($findext) - 1];
4350
        $file_crip = $name_crip.'.'.$extension;
4351
4352
        //copy file to temp/audio directory
4353
        $from_sys = $file_url_sys;
4354
        $to_sys = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/'.$file_crip;
4355
4356
        if (file_exists($from_sys)) {
4357
            copy($from_sys, $to_sys);
4358
        }
4359
4360
        // get file from tmp directory
4361
        Session::write('temp_audio_nanogong', $to_sys);
4362
4363
        return api_get_path(WEB_ARCHIVE_PATH).'temp/audio/'.$file_crip;
4364
    }
4365
4366
    /**
4367
     * Erase temp nanogong audio.
4368
     */
4369
    public static function removeGeneratedAudioTempFile()
4370
    {
4371
        $tempAudio = Session::read('temp_audio_nanogong');
4372
        if (!empty(isset($tempAudio)) && is_file($tempAudio)) {
4373
            unlink($tempAudio);
4374
            Session::erase('temp_audio_nanogong');
4375
        }
4376
    }
4377
4378
    /**
4379
     * Check if the past is used in this course.
4380
     *
4381
     * @param array  $courseInfo
4382
     * @param string $path
4383
     *
4384
     * @return array
4385
     */
4386
    public static function getDocumentByPathInCourse($courseInfo, $path)
4387
    {
4388
        $table = Database::get_course_table(TABLE_DOCUMENT);
4389
        $path = Database::escape_string($path);
4390
        $courseId = $courseInfo['real_id'];
4391
        if (empty($courseId)) {
4392
            return false;
4393
        }
4394
        $sql = "SELECT * FROM $table WHERE c_id = $courseId AND path = '$path'";
4395
        $result = Database::query($sql);
4396
4397
        return Database::store_result($result, 'ASSOC');
4398
    }
4399
4400
    /**
4401
     * @param array $_course
4402
     *
4403
     * @return int
4404
     */
4405
    public static function createDefaultAudioFolder($_course)
4406
    {
4407
        if (!isset($_course['path'])) {
4408
            return false;
4409
        }
4410
4411
        $audioId = null;
4412
        $path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document/';
4413
        if (!is_dir($path.'audio')) {
4414
            mkdir($path.'audio', api_get_permissions_for_new_directories());
4415
            $audioId = add_document($_course, '/audio', 'folder', 0, 'Audio');
4416
            api_item_property_update(
4417
                $_course,
4418
                TOOL_DOCUMENT,
4419
                $audioId,
4420
                'FolderCreated',
4421
                api_get_user_id(),
4422
                null,
4423
                null,
4424
                null,
4425
                null,
4426
                api_get_session_id()
4427
            );
4428
        }
4429
4430
        return $audioId;
4431
    }
4432
4433
    /**
4434
     * Generate a default certificate for a courses.
4435
     *
4436
     * @todo move to certificate lib
4437
     *
4438
     * @global string $css CSS directory
4439
     * @global string $img_dir image directory
4440
     * @global string $default_course_dir Course directory
4441
     * @global string $js JS directory
4442
     *
4443
     * @param array $courseData     The course info
4444
     * @param bool  $fromBaseCourse
4445
     * @param int   $sessionId
4446
     */
4447
    public static function generateDefaultCertificate(
4448
        $courseData,
4449
        $fromBaseCourse = false,
4450
        $sessionId = 0
4451
    ) {
4452
        if (empty($courseData)) {
4453
            return false;
4454
        }
4455
4456
        global $css, $img_dir, $default_course_dir, $js;
4457
        $codePath = api_get_path(REL_CODE_PATH);
4458
        $dir = '/certificates';
4459
        $comment = null;
4460
        $title = get_lang('DefaultCertificate');
4461
        $fileName = api_replace_dangerous_char($title);
4462
        $filePath = api_get_path(SYS_COURSE_PATH)."{$courseData['directory']}/document$dir";
4463
4464
        if (!is_dir($filePath)) {
4465
            mkdir($filePath, api_get_permissions_for_new_directories());
4466
        }
4467
4468
        $fileFullPath = "$filePath/$fileName.html";
4469
        $fileType = 'file';
4470
        $templateContent = file_get_contents(api_get_path(SYS_CODE_PATH).'gradebook/certificate_template/template.html');
4471
4472
        $search = ['{CSS}', '{IMG_DIR}', '{REL_CODE_PATH}', '{COURSE_DIR}'];
4473
        $replace = [$css.$js, $img_dir, $codePath, $default_course_dir];
4474
4475
        $fileContent = str_replace($search, $replace, $templateContent);
4476
        $saveFilePath = "$dir/$fileName.html";
4477
4478
        if ($fromBaseCourse) {
4479
            $defaultCertificateId = self::get_default_certificate_id(
4480
                $courseData['code'],
4481
                0
4482
            );
4483
            if (!empty($defaultCertificateId)) {
4484
                // We have a certificate from the course base
4485
                $documentData = self::get_document_data_by_id(
4486
                    $defaultCertificateId,
4487
                    $courseData['code'],
4488
                    false,
4489
                    0
4490
                );
4491
4492
                if ($documentData) {
4493
                    $fileContent = file_get_contents($documentData['absolute_path']);
4494
                }
4495
            }
4496
        }
4497
4498
        if (file_exists($fileFullPath) === false) {
4499
            $result = file_put_contents($fileFullPath, $fileContent);
4500
            if ($result) {
4501
                $fileSize = filesize($fileFullPath);
4502
4503
                $documentId = add_document(
4504
                    $courseData,
4505
                    $saveFilePath,
4506
                    $fileType,
4507
                    $fileSize,
4508
                    $title,
4509
                    $comment,
4510
                    0, //$readonly = 0,
4511
                    true, //$save_visibility = true,
4512
                    null, //$group_id = null,
4513
                    $sessionId
4514
                );
4515
4516
                api_item_property_update(
4517
                    $courseData,
4518
                    TOOL_DOCUMENT,
4519
                    $documentId,
4520
                    'DocumentAdded',
4521
                    api_get_user_id(),
4522
                    null,
4523
                    null,
4524
                    null,
4525
                    null,
4526
                    $sessionId
4527
                );
4528
4529
                $defaultCertificateId = self::get_default_certificate_id(
4530
                    $courseData['code'],
4531
                    $sessionId
4532
                );
4533
4534
                if (!isset($defaultCertificateId)) {
4535
                    self::attach_gradebook_certificate(
4536
                        $courseData['code'],
4537
                        $documentId,
4538
                        $sessionId
4539
                    );
4540
                }
4541
            }
4542
        }
4543
    }
4544
4545
    /**
4546
     * Update the document name.
4547
     *
4548
     * @param int    $documentId The document id
4549
     * @param string $newName    The new name
4550
     */
4551
    public static function renameDocument($documentId, $newName)
4552
    {
4553
        $documentId = intval($documentId);
4554
        $newName = Database::escape_string($newName);
4555
        $docuentTable = Database::get_course_table(TABLE_DOCUMENT);
4556
4557
        $values = [
4558
            'title' => $newName,
4559
        ];
4560
4561
        $whereConditions = [
4562
            'id = ?' => $documentId,
4563
        ];
4564
4565
        Database::update($docuentTable, $values, $whereConditions);
4566
    }
4567
4568
    /**
4569
     * Get folder/file suffix.
4570
     *
4571
     * @param array $courseInfo
4572
     * @param int   $sessionId
4573
     * @param int   $groupId
4574
     *
4575
     * @return string
4576
     */
4577
    public static function getDocumentSuffix($courseInfo, $sessionId, $groupId)
4578
    {
4579
        // If no session or group, then no suffix.
4580
        if (empty($sessionId) && empty($groupId)) {
4581
            return '';
4582
        }
4583
4584
        return '__'.intval($sessionId).'__'.intval($groupId);
4585
    }
4586
4587
    /**
4588
     * Fix a document name adding session id and group id
4589
     * Turns picture.jpg -> picture__1__2.jpg
4590
     * Where 1 = session id and 2 group id
4591
     * Of session id and group id are empty then the function returns:
4592
     * picture.jpg ->  picture.jpg.
4593
     *
4594
     * @param string $name       folder or file name
4595
     * @param string $type       'folder' or 'file'
4596
     * @param array  $courseInfo
4597
     * @param int    $sessionId
4598
     * @param int    $groupId
4599
     *
4600
     * @return string
4601
     */
4602
    public static function fixDocumentName($name, $type, $courseInfo, $sessionId, $groupId)
4603
    {
4604
        $suffix = self::getDocumentSuffix($courseInfo, $sessionId, $groupId);
4605
4606
        switch ($type) {
4607
            case 'folder':
4608
                $name = $name.$suffix;
4609
                break;
4610
            case 'file':
4611
                $name = self::addSuffixToFileName($name, $suffix);
4612
                break;
4613
        }
4614
4615
        return $name;
4616
    }
4617
4618
    /**
4619
     * Add a suffix to a file Example:
4620
     * /folder/picture.jpg => to /folder/picture_this.jpg
4621
     * where "_this" is the suffix.
4622
     *
4623
     * @param string $name
4624
     * @param string $suffix
4625
     *
4626
     * @return string
4627
     */
4628
    public static function addSuffixToFileName($name, $suffix)
4629
    {
4630
        $extension = pathinfo($name, PATHINFO_EXTENSION);
4631
        $fileName = pathinfo($name, PATHINFO_FILENAME);
4632
        $dir = pathinfo($name, PATHINFO_DIRNAME);
4633
4634
        if ($dir == '.') {
4635
            $dir = null;
4636
        }
4637
4638
        if (!empty($dir) && $dir != '/') {
4639
            $dir = $dir.'/';
4640
        }
4641
4642
        $name = $dir.$fileName.$suffix.'.'.$extension;
4643
4644
        return $name;
4645
    }
4646
4647
    /**
4648
     * Check if folder exist in the course base or in the session course.
4649
     *
4650
     * @param string $folder     Example: /folder/folder2
4651
     * @param array  $courseInfo
4652
     * @param int    $sessionId
4653
     * @param int    $groupId    group.id
4654
     *
4655
     * @return bool
4656
     */
4657
    public static function folderExists(
4658
        $folder,
4659
        $courseInfo,
4660
        $sessionId,
4661
        $groupId
4662
    ) {
4663
        $courseId = $courseInfo['real_id'];
4664
4665
        if (empty($courseId)) {
4666
            return false;
4667
        }
4668
4669
        $sessionId = intval($sessionId);
4670
        $folderWithSuffix = self::fixDocumentName(
4671
            $folder,
4672
            'folder',
4673
            $courseInfo,
4674
            $sessionId,
4675
            $groupId
4676
        );
4677
4678
        $folder = Database::escape_string($folder);
4679
        $folderWithSuffix = Database::escape_string($folderWithSuffix);
4680
4681
        // Check if pathname already exists inside document table
4682
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
4683
        $sql = "SELECT id, path FROM $tbl_document
4684
                WHERE
4685
                    filetype = 'folder' AND
4686
                    c_id = $courseId AND
4687
                    (path = '$folder' OR path = '$folderWithSuffix') AND
4688
                    (session_id = 0 OR session_id = $sessionId)
4689
        ";
4690
4691
        $rs = Database::query($sql);
4692
        if (Database::num_rows($rs)) {
4693
            return true;
4694
        }
4695
4696
        return false;
4697
    }
4698
4699
    /**
4700
     * Check if file exist in the course base or in the session course.
4701
     *
4702
     * @param string $fileName   Example: /folder/picture.jpg
4703
     * @param array  $courseInfo
4704
     * @param int    $sessionId
4705
     * @param int    $groupId
4706
     *
4707
     * @return bool
4708
     */
4709
    public static function documentExists(
4710
        $fileName,
4711
        $courseInfo,
4712
        $sessionId,
4713
        $groupId
4714
    ) {
4715
        $courseId = $courseInfo['real_id'];
4716
4717
        if (empty($courseId)) {
4718
            return false;
4719
        }
4720
4721
        $sessionId = intval($sessionId);
4722
        $fileNameEscape = Database::escape_string($fileName);
4723
4724
        $fileNameWithSuffix = self::fixDocumentName(
4725
            $fileName,
4726
            'file',
4727
            $courseInfo,
4728
            $sessionId,
4729
            $groupId
4730
        );
4731
4732
        $fileNameWithSuffix = Database::escape_string($fileNameWithSuffix);
4733
4734
        // Check if pathname already exists inside document table
4735
        $table = Database::get_course_table(TABLE_DOCUMENT);
4736
        $sql = "SELECT id, path FROM $table
4737
                WHERE
4738
                    filetype = 'file' AND
4739
                    c_id = $courseId AND
4740
                    (
4741
                        path = '".$fileNameEscape."' OR
4742
                        path = '$fileNameWithSuffix'
4743
                    ) AND
4744
                    (session_id = 0 OR session_id = $sessionId)
4745
        ";
4746
        $rs = Database::query($sql);
4747
        if (Database::num_rows($rs)) {
4748
            return true;
4749
        }
4750
4751
        return false;
4752
    }
4753
4754
    /**
4755
     * Undo the suffix applied to a file example:
4756
     * turns picture__1__1.jpg to picture.jpg.
4757
     *
4758
     * @param string $name
4759
     * @param int    $courseId
4760
     * @param int    $sessionId
4761
     * @param int    $groupId
4762
     *
4763
     * @return string
4764
     */
4765
    public static function undoFixDocumentName(
4766
        $name,
4767
        $courseId,
4768
        $sessionId,
4769
        $groupId
4770
    ) {
4771
        if (empty($sessionId) && empty($groupId)) {
4772
            return $name;
4773
        }
4774
4775
        $suffix = self::getDocumentSuffix(
4776
            ['real_id' => $courseId],
4777
            $sessionId,
4778
            $groupId
4779
        );
4780
4781
        $name = str_replace($suffix, '', $name);
4782
4783
        return $name;
4784
    }
4785
4786
    /**
4787
     * @param string $path
4788
     * @param string $name
4789
     * @param array  $courseInfo
4790
     * @param int    $sessionId
4791
     * @param int    $groupId
4792
     *
4793
     * @return string
4794
     */
4795
    public static function getUniqueFileName($path, $name, $courseInfo, $sessionId, $groupId)
4796
    {
4797
        $counter = 1;
4798
        $filePath = $path.$name;
4799
        $uniqueName = $name;
4800
        while ($documentExists = self::documentExists(
4801
            $filePath,
4802
            $courseInfo,
4803
            $sessionId,
4804
            $groupId
4805
        )) {
4806
            $uniqueName = self::addSuffixToFileName($name, '_'.$counter);
4807
            $filePath = $path.$uniqueName;
4808
            $counter++;
4809
        }
4810
4811
        return $uniqueName;
4812
    }
4813
4814
    /**
4815
     * Builds the form that enables the user to
4816
     * select a directory to browse/upload in.
4817
     *
4818
     * @param array    An array containing the folders we want to be able to select
4819
     * @param string    The current folder (path inside of the "document" directory, including the prefix "/")
4820
     * @param string    Group directory, if empty, prevents documents to be uploaded
4821
     * (because group documents cannot be uploaded in root)
4822
     * @param bool    Whether to change the renderer (this will add a template <span>
4823
     * to the QuickForm object displaying the form)
4824
     *
4825
     * @return string html form
4826
     */
4827
    public static function build_directory_selector(
4828
        $folders,
4829
        $document_id,
4830
        $group_dir = '',
4831
        $change_renderer = false,
4832
        &$form = null,
4833
        $selectName = 'id'
4834
    ) {
4835
        $doc_table = Database::get_course_table(TABLE_DOCUMENT);
4836
        $course_id = api_get_course_int_id();
4837
        $folder_titles = [];
4838
4839
        if (is_array($folders)) {
4840
            $escaped_folders = [];
4841
            foreach ($folders as $key => &$val) {
4842
                $escaped_folders[$key] = Database::escape_string($val);
4843
            }
4844
            $folder_sql = implode("','", $escaped_folders);
4845
4846
            $sql = "SELECT path, title 
4847
                    FROM $doc_table
4848
                    WHERE 
4849
                        filetype = 'folder' AND 
4850
                        c_id = $course_id AND 
4851
                        path IN ('".$folder_sql."')";
4852
            $res = Database::query($sql);
4853
            $folder_titles = [];
4854
            while ($obj = Database::fetch_object($res)) {
4855
                $folder_titles[$obj->path] = $obj->title;
4856
            }
4857
        }
4858
4859
        $attributes = [];
4860
        if (empty($form)) {
4861
            $form = new FormValidator('selector', 'GET', api_get_self().'?'.api_get_cidreq());
4862
            $attributes = ['onchange' => 'javascript: document.selector.submit();'];
4863
        }
4864
        $form->addElement('hidden', 'cidReq', api_get_course_id());
4865
        $parent_select = $form->addSelect(
4866
            $selectName,
4867
            get_lang('CurrentDirectory'),
4868
            '',
4869
            $attributes
4870
        );
4871
4872
        // Group documents cannot be uploaded in the root
4873
        if (empty($group_dir)) {
4874
            $parent_select->addOption(get_lang('Documents'), '/');
4875
4876
            if (is_array($folders)) {
4877
                foreach ($folders as $folder_id => &$folder) {
4878
                    $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
4879
                    $path_parts = explode('/', $folder);
4880
                    $folder_titles[$folder] = cut($folder_titles[$folder], 80);
4881
                    $counter = count($path_parts) - 2;
4882
                    if ($counter > 0) {
4883
                        $label = str_repeat('&nbsp;&nbsp;&nbsp;', $counter).' &mdash; '.$folder_titles[$folder];
4884
                    } else {
4885
                        $label = ' &mdash; '.$folder_titles[$folder];
4886
                    }
4887
                    $parent_select->addOption($label, $folder_id);
4888
                    if ($selected != '') {
4889
                        $parent_select->setSelected($folder_id);
4890
                    }
4891
                }
4892
            }
4893
        } else {
4894
            if (!empty($folders)) {
4895
                foreach ($folders as $folder_id => &$folder) {
4896
                    $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
4897
                    $label = $folder_titles[$folder];
4898
                    if ($folder == $group_dir) {
4899
                        $label = get_lang('Documents');
4900
                    } else {
4901
                        $path_parts = explode('/', str_replace($group_dir, '', $folder));
4902
                        $label = cut($label, 80);
4903
                        $label = str_repeat('&nbsp;&nbsp;&nbsp;', count($path_parts) - 2).' &mdash; '.$label;
4904
                    }
4905
                    $parent_select->addOption($label, $folder_id);
4906
                    if ($selected != '') {
4907
                        $parent_select->setSelected($folder_id);
4908
                    }
4909
                }
4910
            }
4911
        }
4912
4913
        $html = $form->toHtml();
4914
4915
        return $html;
4916
    }
4917
4918
    /**
4919
     * Create a html hyperlink depending on if it's a folder or a file.
4920
     *
4921
     * @param string $documentWebPath
4922
     * @param array  $document_data
4923
     * @param bool   $show_as_icon      - if it is true, only a clickable icon will be shown
4924
     * @param int    $visibility        (1/0)
4925
     * @param int    $counter
4926
     * @param int    $size
4927
     * @param bool   $isAllowedToEdit
4928
     * @param bool   $isCertificateMode
4929
     *
4930
     * @return string url
4931
     */
4932
    public static function create_document_link(
4933
        $documentWebPath,
4934
        $document_data,
4935
        $show_as_icon = false,
4936
        $counter = null,
4937
        $visibility,
4938
        $size = 0,
4939
        $isAllowedToEdit = false,
4940
        $isCertificateMode = false
4941
    ) {
4942
        global $dbl_click_id;
4943
        $www = $documentWebPath;
4944
4945
        $sessionId = api_get_session_id();
4946
        $courseParams = api_get_cidreq();
4947
        $webODFList = self::get_web_odf_extension_list();
4948
4949
        // Get the title or the basename depending on what we're using
4950
        if ($document_data['title'] != '') {
4951
            $title = $document_data['title'];
4952
        } else {
4953
            $title = basename($document_data['path']);
4954
        }
4955
4956
        $filetype = $document_data['filetype'];
4957
        $path = $document_data['path'];
4958
        $url_path = urlencode($document_data['path']);
4959
4960
        // Add class="invisible" on invisible files
4961
        $visibility_class = $visibility == false ? ' class="muted"' : '';
4962
        $forcedownload_link = '';
4963
        $forcedownload_icon = '';
4964
        $prevent_multiple_click = '';
4965
        $force_download_html = '';
4966
4967
        if (!$show_as_icon) {
4968
            // Build download link (icon)
4969
            $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'];
4970
            // Folder download or file download?
4971
            $forcedownload_icon = $filetype == 'folder' ? 'save_pack.png' : 'save.png';
4972
            // Prevent multiple clicks on zipped folder download
4973
            $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; }\"" : '';
4974
        }
4975
4976
        $target = '_self';
4977
        $is_browser_viewable_file = false;
4978
4979
        if ($filetype == 'file') {
4980
            // Check the extension
4981
            $ext = explode('.', $path);
4982
            $ext = strtolower($ext[sizeof($ext) - 1]);
4983
4984
            // HTML-files an some other types are shown in a frameset by default.
4985
            $is_browser_viewable_file = self::isBrowserViewable($ext);
4986
            if ($is_browser_viewable_file) {
4987
                if ($ext == 'pdf' || in_array($ext, $webODFList)) {
4988
                    $url = api_get_self().'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
4989
                } else {
4990
                    $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
4991
                }
4992
            } else {
4993
                // url-encode for problematic characters (we may not call them dangerous characters...)
4994
                //$path = str_replace('%2F', '/', $url_path).'?'.$courseParams;
4995
                $url = $www.str_replace('%2F', '/', $url_path).'?'.$courseParams;
4996
            }
4997
        } else {
4998
            $url = api_get_self().'?'.$courseParams.'&id='.$document_data['id'];
4999
        }
5000
5001
        if ($isCertificateMode) {
5002
            $url .= '&certificate=true&selectcat='.(isset($_GET['selectcat']) ? $_GET['selectcat'] : '');
5003
        }
5004
5005
        // The little download icon
5006
        $tooltip_title = $title;
5007
        $tooltip_title_alt = $tooltip_title;
5008
5009
        if ($filetype == 'link') {
5010
            $tooltip_title_alt = $title;
5011
            $url = $document_data['comment'].'" target="_blank';
5012
        }
5013
5014
        if ($path == '/shared_folder') {
5015
            $tooltip_title_alt = get_lang('UserFolders');
5016
        } elseif (strstr($path, 'shared_folder_session_')) {
5017
            $tooltip_title_alt = get_lang('UserFolders').' ('.api_get_session_name(api_get_session_id()).')';
5018
        } elseif (strstr($tooltip_title, 'sf_user_')) {
5019
            $userinfo = api_get_user_info(substr($tooltip_title, 8));
5020
            $tooltip_title_alt = get_lang('UserFolder').' '.$userinfo['complete_name'];
5021
        } elseif ($path == '/chat_files') {
5022
            $tooltip_title_alt = get_lang('ChatFiles');
5023
        } elseif ($path == '/learning_path') {
5024
            $tooltip_title_alt = get_lang('LearningPaths');
5025
        } elseif ($path == '/video') {
5026
            $tooltip_title_alt = get_lang('Video');
5027
        } elseif ($path == '/audio') {
5028
            $tooltip_title_alt = get_lang('Audio');
5029
        } elseif ($path == '/flash') {
5030
            $tooltip_title_alt = get_lang('Flash');
5031
        } elseif ($path == '/images') {
5032
            $tooltip_title_alt = get_lang('Images');
5033
        } elseif ($path == '/images/gallery') {
5034
            $tooltip_title_alt = get_lang('DefaultCourseImages');
5035
        }
5036
5037
        $copyToMyFiles = $open_in_new_window_link = '';
5038
        $curdirpath = isset($_GET['curdirpath']) ? Security::remove_XSS($_GET['curdirpath']) : null;
5039
        $send_to = null;
5040
        $checkExtension = $path;
5041
        $extension = pathinfo($path, PATHINFO_EXTENSION);
5042
        $document_data['file_extension'] = $extension;
5043
5044
        if (!$show_as_icon) {
5045
            if ($filetype == 'folder') {
5046
                if ($isAllowedToEdit ||
5047
                    api_is_platform_admin() ||
5048
                    api_get_setting('students_download_folders') == 'true'
5049
                ) {
5050
                    // filter: when I am into a shared folder, I can only show "my shared folder" for donwload
5051
                    if (self::is_shared_folder($curdirpath, $sessionId)) {
5052
                        if (preg_match('/shared_folder\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
5053
                            preg_match('/shared_folder_session_'.$sessionId.'\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
5054
                            $isAllowedToEdit || api_is_platform_admin()
5055
                        ) {
5056
                            $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5057
                                Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5058
                        }
5059
                    } elseif (!preg_match('/shared_folder/', urldecode($forcedownload_link)) ||
5060
                        $isAllowedToEdit ||
5061
                        api_is_platform_admin()
5062
                    ) {
5063
                        $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5064
                            Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5065
                    }
5066
                }
5067
            } else {
5068
                $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.' download="'.$document_data['basename'].'">'.
5069
                    Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5070
            }
5071
5072
            // Copy files to user's myfiles
5073
            if (api_get_setting('allow_my_files') === 'true' &&
5074
                api_get_setting('users_copy_files') === 'true' && api_is_anonymous() === false
5075
            ) {
5076
                $copy_myfiles_link = $filetype == 'file' ? api_get_self().'?'.$courseParams.'&action=copytomyfiles&id='.$document_data['id'] : api_get_self().'?'.$courseParams;
5077
                if ($filetype == 'file') {
5078
                    $copyToMyFiles = '<a href="'.$copy_myfiles_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5079
                        Display::return_icon('briefcase.png', get_lang('CopyToMyFiles'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
5080
5081
                    if (api_get_setting('allow_my_files') === 'false') {
5082
                        $copyToMyFiles = '';
5083
                    }
5084
                }
5085
            }
5086
5087
            $pdf_icon = '';
5088
            if (!$isAllowedToEdit &&
5089
                api_get_setting('students_export2pdf') == 'true' &&
5090
                $filetype == 'file' &&
5091
                in_array($extension, ['html', 'htm'])
5092
            ) {
5093
                $pdf_icon = ' <a style="float:right".'.$prevent_multiple_click.' href="'.api_get_self().'?'.$courseParams.'&action=export_to_pdf&id='.$document_data['id'].'&curdirpath='.$curdirpath.'">'.
5094
                    Display::return_icon('pdf.png', get_lang('Export2PDF'), [], ICON_SIZE_SMALL).'</a> ';
5095
            }
5096
5097
            if ($is_browser_viewable_file) {
5098
                $open_in_new_window_link = '<a href="'.$www.str_replace('%2F', '/', $url_path).'?'.$courseParams.'" style="float:right"'.$prevent_multiple_click.' target="_blank">'.
5099
                    Display::return_icon('open_in_new_window.png', get_lang('OpenInANewWindow'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
5100
            }
5101
5102
            if ($filetype == 'file') {
5103
                // Sound preview
5104
                if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5105
                    (preg_match('/wav$/i', urldecode($checkExtension))) ||
5106
                    preg_match('/ogg$/i', urldecode($checkExtension))
5107
                ) {
5108
                    return '<span style="float:left" '.$visibility_class.'>'.
5109
                    $title.
5110
                    '</span>'.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5111
                } elseif (
5112
                    // Show preview
5113
                    preg_match('/swf$/i', urldecode($checkExtension)) ||
5114
                    preg_match('/png$/i', urldecode($checkExtension)) ||
5115
                    preg_match('/gif$/i', urldecode($checkExtension)) ||
5116
                    preg_match('/jpg$/i', urldecode($checkExtension)) ||
5117
                    preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5118
                    preg_match('/bmp$/i', urldecode($checkExtension)) ||
5119
                    preg_match('/svg$/i', urldecode($checkExtension))
5120
                ) {
5121
                    // Simpler version of showinframesmin.php with no headers
5122
                    $url = 'show_content.php?'.$courseParams.'&id='.$document_data['id'];
5123
                    $class = 'ajax';
5124
                    if ($visibility == false) {
5125
                        $class = "ajax text-muted";
5126
                    }
5127
5128
                    return Display::url(
5129
                        $title,
5130
                        $url,
5131
                        [
5132
                            'class' => $class,
5133
                            'title' => $tooltip_title_alt,
5134
                            'data-title' => $title,
5135
                            'style' => 'float:left;',
5136
                        ]
5137
                    )
5138
                    .$force_download_html.$send_to.$copyToMyFiles
5139
                    .$open_in_new_window_link.$pdf_icon;
5140
                } else {
5141
                    // For a "PDF Download" of the file.
5142
                    $pdfPreview = null;
5143
                    if ($ext != 'pdf' && !in_array($ext, $webODFList)) {
5144
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
5145
                    } else {
5146
                        $pdfPreview = Display::url(
5147
                            Display::return_icon('preview.png', get_lang('Preview'), null, ICON_SIZE_SMALL),
5148
                            api_get_path(WEB_CODE_PATH).'document/showinframes.php?'.$courseParams.'&id='.$document_data['id'],
5149
                            ['style' => 'float:right']
5150
                        );
5151
                    }
5152
                    // No plugin just the old and good showinframes.php page
5153
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" style="float:left" '.$visibility_class.' >'.$title.'</a>'.
5154
                    $pdfPreview.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5155
                }
5156
            } else {
5157
                return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.$title.'</a>'.
5158
                $force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5159
            }
5160
            // end copy files to users myfiles
5161
        } else {
5162
            // Icon column
5163
            if (preg_match('/shared_folder/', urldecode($checkExtension)) &&
5164
                preg_match('/shared_folder$/', urldecode($checkExtension)) == false &&
5165
                preg_match('/shared_folder_session_'.$sessionId.'$/', urldecode($url)) == false
5166
            ) {
5167
                if ($filetype == 'file') {
5168
                    //Sound preview
5169
                    if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5170
                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
5171
                        preg_match('/ogg$/i', urldecode($checkExtension))) {
5172
                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
5173
5174
                        return $soundPreview;
5175
                    } elseif (
5176
                        // Show preview
5177
                        preg_match('/swf$/i', urldecode($checkExtension)) ||
5178
                        preg_match('/png$/i', urldecode($checkExtension)) ||
5179
                        preg_match('/gif$/i', urldecode($checkExtension)) ||
5180
                        preg_match('/jpg$/i', urldecode($checkExtension)) ||
5181
                        preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5182
                        preg_match('/bmp$/i', urldecode($checkExtension)) ||
5183
                        preg_match('/svg$/i', urldecode($checkExtension))
5184
                    ) {
5185
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
5186
5187
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5188
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5189
                            Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5190
                        '</a>';
5191
                    } else {
5192
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5193
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5194
                            Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5195
                        '</a>';
5196
                    }
5197
                } else {
5198
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
5199
                        self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5200
                        Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5201
                    '</a>';
5202
                }
5203
            } else {
5204
                if ($filetype == 'file') {
5205
                    // Sound preview with jplayer
5206
                    if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5207
                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
5208
                        preg_match('/ogg$/i', urldecode($checkExtension))) {
5209
                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
5210
5211
                        return $soundPreview;
5212
                    } elseif (
5213
                        //Show preview
5214
                        preg_match('/html$/i', urldecode($checkExtension)) ||
5215
                        preg_match('/htm$/i', urldecode($checkExtension)) ||
5216
                        preg_match('/swf$/i', urldecode($checkExtension)) ||
5217
                        preg_match('/png$/i', urldecode($checkExtension)) ||
5218
                        preg_match('/gif$/i', urldecode($checkExtension)) ||
5219
                        preg_match('/jpg$/i', urldecode($checkExtension)) ||
5220
                        preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5221
                        preg_match('/bmp$/i', urldecode($checkExtension)) ||
5222
                        preg_match('/svg$/i', urldecode($checkExtension))
5223
                    ) {
5224
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id']; //without preview
5225
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5226
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5227
                        '</a>';
5228
                    } else {
5229
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5230
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5231
                        '</a>';
5232
                    }
5233
                } else {
5234
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
5235
                        self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5236
                    '</a>';
5237
                }
5238
            }
5239
        }
5240
    }
5241
5242
    /**
5243
     * Builds an img html tag for the file type.
5244
     *
5245
     * @param string $type            (file/folder)
5246
     * @param string $path
5247
     * @param bool   $isAllowedToEdit
5248
     *
5249
     * @return string img html tag
5250
     */
5251
    public static function build_document_icon_tag($type, $path, $isAllowedToEdit = null)
5252
    {
5253
        $basename = basename($path);
5254
        $sessionId = api_get_session_id();
5255
        if (is_null($isAllowedToEdit)) {
5256
            $isAllowedToEdit = api_is_allowed_to_edit(null, true);
5257
        }
5258
        $user_image = false;
5259
        if ($type == 'file') {
5260
            $icon = choose_image($basename);
5261
            $basename = substr(strrchr($basename, '.'), 1);
5262
        } elseif ($type == 'link') {
5263
            $icon = 'clouddoc.png';
5264
            $basename = get_lang('CloudFileLink');
5265
        } else {
5266
            if ($path == '/shared_folder') {
5267
                $icon = 'folder_users.png';
5268
                if ($isAllowedToEdit) {
5269
                    $basename = get_lang('HelpUsersFolder');
5270
                } else {
5271
                    $basename = get_lang('UserFolders');
5272
                }
5273
            } elseif (strstr($basename, 'sf_user_')) {
5274
                $userInfo = api_get_user_info(substr($basename, 8));
5275
                $icon = $userInfo['avatar_small'];
5276
                $basename = get_lang('UserFolder').' '.$userInfo['complete_name'];
5277
                $user_image = true;
5278
            } elseif (strstr($path, 'shared_folder_session_')) {
5279
                $sessionName = api_get_session_name($sessionId);
5280
                if ($isAllowedToEdit) {
5281
                    $basename = '***('.$sessionName.')*** '.get_lang('HelpUsersFolder');
5282
                } else {
5283
                    $basename = get_lang('UserFolders').' ('.$sessionName.')';
5284
                }
5285
                $icon = 'folder_users.png';
5286
            } else {
5287
                $icon = 'folder_document.png';
5288
5289
                if ($path == '/audio') {
5290
                    $icon = 'folder_audio.png';
5291
                    if ($isAllowedToEdit) {
5292
                        $basename = get_lang('HelpDefaultDirDocuments');
5293
                    } else {
5294
                        $basename = get_lang('Audio');
5295
                    }
5296
                } elseif ($path == '/flash') {
5297
                    $icon = 'folder_flash.png';
5298
                    if ($isAllowedToEdit) {
5299
                        $basename = get_lang('HelpDefaultDirDocuments');
5300
                    } else {
5301
                        $basename = get_lang('Flash');
5302
                    }
5303
                } elseif ($path == '/images') {
5304
                    $icon = 'folder_images.png';
5305
                    if ($isAllowedToEdit) {
5306
                        $basename = get_lang('HelpDefaultDirDocuments');
5307
                    } else {
5308
                        $basename = get_lang('Images');
5309
                    }
5310
                } elseif ($path == '/video') {
5311
                    $icon = 'folder_video.png';
5312
                    if ($isAllowedToEdit) {
5313
                        $basename = get_lang('HelpDefaultDirDocuments');
5314
                    } else {
5315
                        $basename = get_lang('Video');
5316
                    }
5317
                } elseif ($path == '/images/gallery') {
5318
                    $icon = 'folder_gallery.png';
5319
                    if ($isAllowedToEdit) {
5320
                        $basename = get_lang('HelpDefaultDirDocuments');
5321
                    } else {
5322
                        $basename = get_lang('Gallery');
5323
                    }
5324
                } elseif ($path == '/chat_files') {
5325
                    $icon = 'folder_chat.png';
5326
                    if ($isAllowedToEdit) {
5327
                        $basename = get_lang('HelpFolderChat');
5328
                    } else {
5329
                        $basename = get_lang('ChatFiles');
5330
                    }
5331
                } elseif ($path == '/learning_path') {
5332
                    $icon = 'folder_learningpath.png';
5333
                    if ($isAllowedToEdit) {
5334
                        $basename = get_lang('HelpFolderLearningPaths');
5335
                    } else {
5336
                        $basename = get_lang('LearningPaths');
5337
                    }
5338
                }
5339
            }
5340
        }
5341
5342
        if ($user_image) {
5343
            return Display::img($icon, $basename, [], false);
5344
        }
5345
5346
        return Display::return_icon($icon, $basename, [], ICON_SIZE_SMALL);
5347
    }
5348
5349
    /**
5350
     * Creates the row of edit icons for a file/folder.
5351
     *
5352
     * @param array $document_data
5353
     * @param int   $id
5354
     * @param bool  $is_template
5355
     * @param int   $is_read_only
5356
     * @param int   $visibility    (1/0)
5357
     *
5358
     * @return string html img tags with hyperlinks
5359
     */
5360
    public static function build_edit_icons($document_data, $id, $is_template, $is_read_only = 0, $visibility)
5361
    {
5362
        $sessionId = api_get_session_id();
5363
        $courseParams = api_get_cidreq();
5364
        $document_id = $document_data['id'];
5365
        $type = $document_data['filetype'];
5366
        $is_read_only = $document_data['readonly'];
5367
        $path = $document_data['path'];
5368
5369
        if ($type == 'link') {
5370
            $parent_id = self::get_document_id(
5371
                api_get_course_info(),
5372
                rtrim($path, '/'),
5373
                0
5374
            );
5375
        } else {
5376
            $parent_id = self::get_document_id(
5377
                api_get_course_info(),
5378
                dirname($path),
5379
                0
5380
            );
5381
        }
5382
5383
        if (empty($parent_id) && !empty($sessionId)) {
5384
            $parent_id = self::get_document_id(
5385
                api_get_course_info(),
5386
                dirname($path),
5387
                $sessionId
5388
            );
5389
        }
5390
5391
        $curdirpath = dirname($document_data['path']);
5392
        $is_certificate_mode = self::is_certificate_mode($path);
5393
        $curdirpath = urlencode($curdirpath);
5394
        $extension = pathinfo($path, PATHINFO_EXTENSION);
5395
        //@todo Implement remote support for converter
5396
        $usePpt2lp = api_get_setting('service_ppt2lp', 'active') == 'true' && api_get_setting('service_ppt2lp', 'host') == 'localhost';
5397
        $formatTypeList = self::getFormatTypeListConvertor('from', $extension);
5398
        $formatType = current($formatTypeList);
5399
5400
        // If document is read only *or* we're in a session and the document
5401
        // is from a non-session context, hide the edition capabilities
5402
        $modify_icons = [];
5403
        $modify_icons[] = self::getButtonEdit($is_read_only, $document_data, $extension, $is_certificate_mode);
5404
        $modify_icons[] = self::getButtonMove($is_read_only, $document_data, $is_certificate_mode, $parent_id);
5405
        $modify_icons[] = self::getButtonVisibility(
5406
            $is_read_only,
5407
            $visibility,
5408
            $document_data,
5409
            $is_certificate_mode,
5410
            $parent_id
5411
        );
5412
        $modify_icons[] = self::getButtonDelete(
5413
            $is_read_only,
5414
            $document_data,
5415
            $is_certificate_mode,
5416
            $curdirpath,
5417
            $parent_id
5418
        );
5419
5420
        if (!$is_read_only /* or ($session_id!=api_get_session_id()) */) {
5421
            // Add action to covert to PDF, will create a new document whit same filename but .pdf extension
5422
            // @TODO: add prompt to select a format target
5423
            if (!in_array($path, self::get_system_folders())) {
5424
                if ($usePpt2lp && $formatType) {
5425
                    $modify_icons[] = Display::url(
5426
                        Display::return_icon('convert.png', get_lang('Convert')),
5427
                        '#',
5428
                        ['class' => 'convertAction', 'data-documentId' => $document_id, 'data-formatType' => $formatType]
5429
                    );
5430
                }
5431
            }
5432
        }
5433
5434
        if ($type == 'file' && ($extension == 'html' || $extension == 'htm')) {
5435
            if ($is_template == 0) {
5436
                if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] != '/certificates') || !isset($_GET['curdirpath'])) {
5437
                    $modify_icons[] = Display::url(
5438
                        Display::return_icon('wizard.png', get_lang('AddAsTemplate')),
5439
                        api_get_self()."?$courseParams&curdirpath=$curdirpath&add_as_template=$id"
5440
                    );
5441
                }
5442
                if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] == '/certificates') || $is_certificate_mode) {//allow attach certificate to course
5443
                    $visibility_icon_certificate = 'nocertificate';
5444
                    if (self::get_default_certificate_id(api_get_course_id()) == $id) {
5445
                        $visibility_icon_certificate = 'certificate';
5446
                        $certificate = get_lang('DefaultCertificate');
5447
                        $preview = get_lang('PreviewCertificate');
5448
                        $is_preview = true;
5449
                    } else {
5450
                        $is_preview = false;
5451
                        $certificate = get_lang('NoDefaultCertificate');
5452
                    }
5453
                    if (isset($_GET['selectcat'])) {
5454
                        $modify_icons[] = Display::url(
5455
                            Display::return_icon($visibility_icon_certificate.'.png', $certificate),
5456
                            api_get_self()."?$courseParams&curdirpath=$curdirpath&selectcat=".intval($_GET['selectcat'])."&set_certificate=$id"
5457
                        );
5458
                        if ($is_preview) {
5459
                            $modify_icons[] = Display::url(
5460
                                Display::return_icon('preview_view.png', $preview),
5461
                                api_get_self()."?$courseParams&curdirpath=$curdirpath&set_preview=$id"
5462
                            );
5463
                        }
5464
                    }
5465
                }
5466
            } else {
5467
                $modify_icons[] = Display::url(
5468
                    Display::return_icon('wizard_na.png', get_lang('RemoveAsTemplate')),
5469
                    api_get_self()."?$courseParams&curdirpath=$curdirpath&remove_as_template=$id"
5470
                );
5471
            }
5472
5473
            $modify_icons[] = Display::url(
5474
                Display::return_icon('pdf.png', get_lang('Export2PDF')),
5475
                api_get_self()."?$courseParams&action=export_to_pdf&id=$id&curdirpath=$curdirpath"
5476
            );
5477
        }
5478
5479
        return implode(PHP_EOL, $modify_icons);
5480
    }
5481
5482
    /**
5483
     * @param $folders
5484
     * @param $curdirpath
5485
     * @param $move_file
5486
     * @param string $group_dir
5487
     *
5488
     * @return string
5489
     */
5490
    public static function build_move_to_selector($folders, $curdirpath, $move_file, $group_dir = '')
5491
    {
5492
        $form = new FormValidator('move_to', 'post', api_get_self().'?'.api_get_cidreq());
5493
5494
        // Form title
5495
        $form->addHidden('move_file', $move_file);
5496
5497
        $options = [];
5498
5499
        // Group documents cannot be uploaded in the root
5500
        if ($group_dir == '') {
5501
            if ($curdirpath != '/') {
5502
                $options['/'] = get_lang('Documents');
5503
            }
5504
5505
            if (is_array($folders)) {
5506
                foreach ($folders as &$folder) {
5507
                    // Hide some folders
5508
                    if ($folder == '/HotPotatoes_files' ||
5509
                        $folder == '/certificates' ||
5510
                        basename($folder) == 'css'
5511
                    ) {
5512
                        continue;
5513
                    }
5514
                    // Admin setting for Hide/Show the folders of all users
5515
                    if (api_get_setting('show_users_folders') == 'false' &&
5516
                        (strstr($folder, '/shared_folder') || strstr($folder, 'shared_folder_session_'))
5517
                    ) {
5518
                        continue;
5519
                    }
5520
5521
                    // Admin setting for Hide/Show Default folders to all users
5522
                    if (api_get_setting('show_default_folders') == 'false' &&
5523
                        (
5524
                            $folder == '/images' ||
5525
                            $folder == '/flash' ||
5526
                            $folder == '/audio' ||
5527
                            $folder == '/video' ||
5528
                            strstr($folder, '/images/gallery') ||
5529
                            $folder == '/video/flv'
5530
                        )
5531
                    ) {
5532
                        continue;
5533
                    }
5534
5535
                    // Admin setting for Hide/Show chat history folder
5536
                    if (api_get_setting('show_chat_folder') == 'false' &&
5537
                        $folder == '/chat_files') {
5538
                        continue;
5539
                    }
5540
5541
                    // You cannot move a file to:
5542
                    // 1. current directory
5543
                    // 2. inside the folder you want to move
5544
                    // 3. inside a subfolder of the folder you want to move
5545
                    if (($curdirpath != $folder) &&
5546
                        ($folder != $move_file) &&
5547
                        (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
5548
                    ) {
5549
                        $path_displayed = $folder;
5550
                        // If document title is used, we have to display titles instead of real paths...
5551
                        $path_displayed = self::get_titles_of_path($folder);
5552
5553
                        if (empty($path_displayed)) {
5554
                            $path_displayed = get_lang('Untitled');
5555
                        }
5556
                        $options[$folder] = $path_displayed;
5557
                    }
5558
                }
5559
            }
5560
        } else {
5561
            foreach ($folders as $folder) {
5562
                if (($curdirpath != $folder) &&
5563
                    ($folder != $move_file) &&
5564
                    (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
5565
                ) {
5566
                    // Cannot copy dir into his own subdir
5567
                    $path_displayed = self::get_titles_of_path($folder);
5568
                    $display_folder = substr($path_displayed, strlen($group_dir));
5569
                    $display_folder = ($display_folder == '') ? get_lang('Documents') : $display_folder;
5570
                    //$form .= '<option value="'.$folder.'">'.$display_folder.'</option>';
5571
                    $options[$folder] = $display_folder;
5572
                }
5573
            }
5574
        }
5575
        $form->addElement('select', 'move_to', get_lang('MoveTo'), $options);
5576
        $form->addButtonNext(get_lang('MoveElement'), 'move_file_submit');
5577
5578
        return $form->returnForm();
5579
    }
5580
5581
    /**
5582
     * Gets the path translated with title of docs and folders.
5583
     *
5584
     * @param string $path the real path
5585
     *
5586
     * @return the path which should be displayed
5587
     */
5588
    public static function get_titles_of_path($path)
5589
    {
5590
        global $tmp_folders_titles;
5591
        $course_id = api_get_course_int_id();
5592
        $nb_slashes = substr_count($path, '/');
5593
        $current_slash_pos = 0;
5594
        $path_displayed = '';
5595
        for ($i = 0; $i < $nb_slashes; $i++) {
5596
            // For each folder of the path, retrieve title.
5597
            $current_slash_pos = strpos($path, '/', $current_slash_pos + 1);
5598
            $tmp_path = substr($path, strpos($path, '/', 0), $current_slash_pos);
5599
5600
            if (empty($tmp_path)) {
5601
                // If empty, then we are in the final part of the path
5602
                $tmp_path = $path;
5603
            }
5604
5605
            if (!empty($tmp_folders_titles[$tmp_path])) {
5606
                // If this path has soon been stored here we don't need a new query
5607
                $path_displayed .= $tmp_folders_titles[$tmp_path];
5608
            } else {
5609
                $sql = 'SELECT title FROM '.Database::get_course_table(TABLE_DOCUMENT).'
5610
                        WHERE c_id = '.$course_id.' AND path LIKE BINARY "'.$tmp_path.'"';
5611
                $rs = Database::query($sql);
5612
                $tmp_title = '/'.Database::result($rs, 0, 0);
5613
                $path_displayed .= $tmp_title;
5614
                $tmp_folders_titles[$tmp_path] = $tmp_title;
5615
            }
5616
        }
5617
5618
        return $path_displayed;
5619
    }
5620
5621
    /**
5622
     * Creates form that asks for the directory name.
5623
     *
5624
     * @return string html-output text for the form
5625
     */
5626
    public static function create_dir_form($dirId)
5627
    {
5628
        global $document_id;
5629
        $form = new FormValidator('create_dir_form', 'post', api_get_self().'?'.api_get_cidreq());
5630
        $form->addElement('hidden', 'create_dir', 1);
5631
        $form->addElement('hidden', 'dir_id', intval($document_id));
5632
        $form->addElement('hidden', 'id', intval($dirId));
5633
        $form->addElement('header', get_lang('CreateDir'));
5634
        $form->addText('dirname', get_lang('NewDir'), ['autofocus' => 'autofocus']);
5635
        $form->addButtonCreate(get_lang('CreateFolder'));
5636
5637
        return $form->returnForm();
5638
    }
5639
5640
    /**
5641
     * Checks whether the user is in shared folder.
5642
     *
5643
     * @param string $curdirpath
5644
     * @param int    $sessionId
5645
     *
5646
     * @return bool Return true when user is into shared folder
5647
     */
5648
    public static function is_shared_folder($curdirpath, $sessionId)
5649
    {
5650
        $clean_curdirpath = Security::remove_XSS($curdirpath);
5651
        if ($clean_curdirpath == '/shared_folder') {
5652
            return true;
5653
        } elseif ($clean_curdirpath == '/shared_folder_session_'.$sessionId) {
5654
            return true;
5655
        } else {
5656
            return false;
5657
        }
5658
    }
5659
5660
    /**
5661
     * Checks whether the user is into any user shared folder.
5662
     *
5663
     * @param string $path
5664
     * @param int    $sessionId
5665
     *
5666
     * @return bool Return true when user is in any user shared folder
5667
     */
5668
    public static function is_any_user_shared_folder($path, $sessionId)
5669
    {
5670
        $clean_path = Security::remove_XSS($path);
5671
        if (strpos($clean_path, 'shared_folder/sf_user_')) {
5672
            return true;
5673
        } elseif (strpos($clean_path, 'shared_folder_session_'.$sessionId.'/sf_user_')) {
5674
            return true;
5675
        } else {
5676
            return false;
5677
        }
5678
    }
5679
5680
    /**
5681
     * Create users shared folder for course.
5682
     *
5683
     * @param int   $userId
5684
     * @param array $courseInfo
5685
     * @param int   $sessionId
5686
     */
5687
    public static function createUserSharedFolder($userId, array $courseInfo, $sessionId = 0)
5688
    {
5689
        $documentDirectory = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document';
5690
        $userInfo = api_get_user_info($userId);
5691
5692
        if (!$sessionId) {
5693
            //Create shared folder. Necessary for recycled courses.
5694
            if (!file_exists($documentDirectory.'/shared_folder')) {
5695
                create_unexisting_directory(
5696
                    $courseInfo,
5697
                    $userId,
5698
                    0,
5699
                    0,
5700
                    0,
5701
                    $documentDirectory,
5702
                    '/shared_folder',
5703
                    get_lang('UserFolders'),
5704
                    0,
5705
                    false,
5706
                    false
5707
                );
5708
            }
5709
            // Create dynamic user shared folder
5710
            if (!file_exists($documentDirectory.'/shared_folder/sf_user_'.$userId)) {
5711
                create_unexisting_directory(
5712
                    $courseInfo,
5713
                    $userId,
5714
                    0,
5715
                    0,
5716
                    0,
5717
                    $documentDirectory,
5718
                    '/shared_folder/sf_user_'.$userId,
5719
                    $userInfo['complete_name'],
5720
                    1,
5721
                    false,
5722
                    false
5723
                );
5724
            }
5725
5726
            return;
5727
        }
5728
5729
        // Create shared folder session.
5730
        if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId)) {
5731
            create_unexisting_directory(
5732
                $courseInfo,
5733
                api_get_user_id(),
5734
                $sessionId,
5735
                0,
5736
                0,
5737
                $documentDirectory,
5738
                '/shared_folder_session_'.$sessionId,
5739
                get_lang('UserFolders').' ('.api_get_session_name($sessionId).')',
5740
                0,
5741
                false,
5742
                false
5743
            );
5744
        }
5745
        //Create dynamic user shared folder into a shared folder session
5746
        if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId.'/sf_user_'.$userId)) {
5747
            create_unexisting_directory(
5748
                $courseInfo,
5749
                $userId,
5750
                $sessionId,
5751
                0,
5752
                0,
5753
                $documentDirectory,
5754
                '/shared_folder_session_'.$sessionId.'/sf_user_'.$userId,
5755
                $userInfo['complete_name'].'('.api_get_session_name($sessionId).')',
5756
                1,
5757
                false,
5758
                false
5759
            );
5760
        }
5761
    }
5762
5763
    /**
5764
     * Checks whether the user is into his shared folder or into a subfolder.
5765
     *
5766
     * @param int    $user_id
5767
     * @param string $path
5768
     * @param int    $sessionId
5769
     *
5770
     * @return bool Return true when user is in his user shared folder or into a subfolder
5771
     */
5772
    public static function is_my_shared_folder($user_id, $path, $sessionId)
5773
    {
5774
        $clean_path = Security::remove_XSS($path).'/';
5775
        //for security does not remove the last slash
5776
        $main_user_shared_folder = '/shared_folder\/sf_user_'.$user_id.'\//';
5777
        //for security does not remove the last slash
5778
        $main_user_shared_folder_session = '/shared_folder_session_'.$sessionId.'\/sf_user_'.$user_id.'\//';
5779
5780
        if (preg_match($main_user_shared_folder, $clean_path)) {
5781
            return true;
5782
        } elseif (preg_match($main_user_shared_folder_session, $clean_path)) {
5783
            return true;
5784
        } else {
5785
            return false;
5786
        }
5787
    }
5788
5789
    /**
5790
     * Check if the file name or folder searched exist.
5791
     *
5792
     * @return bool Return true when exist
5793
     */
5794
    public static function search_keyword($document_name, $keyword)
5795
    {
5796
        if (api_strripos($document_name, $keyword) !== false) {
5797
            return true;
5798
        } else {
5799
            return false;
5800
        }
5801
    }
5802
5803
    /**
5804
     * Checks whether a document can be previewed by using the browser.
5805
     *
5806
     * @param string $file_extension the filename extension of the document (it must be in lower case)
5807
     *
5808
     * @return bool returns TRUE or FALSE
5809
     */
5810
    public static function isBrowserViewable($file_extension)
5811
    {
5812
        static $allowed_extensions = [
5813
            'htm', 'html', 'xhtml',
5814
            'gif', 'jpg', 'jpeg', 'png', 'tif', 'tiff',
5815
            'pdf', 'svg', 'swf',
5816
            'txt', 'log',
5817
            'mp4', 'ogg', 'ogv', 'ogx', 'mpg', 'mpeg', 'mov', 'avi', 'webm', 'wmv',
5818
            'mp3', 'oga', 'wav', 'au', 'wma', 'mid', 'kar',
5819
        ];
5820
5821
        /*
5822
          //TODO: make a admin switch to strict mode
5823
          1. global default $allowed_extensions
5824
          if (in_array($file_extension, $allowed_extensions)) { // Assignment + a logical check.
5825
          return true;
5826
          }
5827
          2. check native support
5828
          3. check plugins: quicktime, mediaplayer, vlc, acrobat, flash, java
5829
         */
5830
5831
        if (!($result = in_array($file_extension, $allowed_extensions))) {
5832
            // Assignment + a logical check.
5833
            return false;
5834
        }
5835
5836
        //check native support (Explorer, Opera, Firefox, Chrome, Safari)
5837
        if ($file_extension == "pdf") {
5838
            return api_browser_support('pdf');
5839
        } elseif ($file_extension == "mp3") {
5840
            return api_browser_support('mp3');
5841
        } elseif ($file_extension == "mp4") {
5842
            return api_browser_support('mp4');
5843
        } elseif ($file_extension == "ogg" || $file_extension == "ogx" || $file_extension == "ogv" || $file_extension == "oga") {
5844
            return api_browser_support('ogg');
5845
        } elseif ($file_extension == "svg") {
5846
            return api_browser_support('svg');
5847
        } elseif ($file_extension == "mpg" || $file_extension == "mpeg") {
5848
            return api_browser_support('mpg');
5849
        } elseif ($file_extension == "mov") {
5850
            return api_browser_support('mov');
5851
        } elseif ($file_extension == "wav") {
5852
            return api_browser_support('wav');
5853
        } elseif ($file_extension == "mid" || $file_extension == "kar") {
5854
            return api_browser_support('mid');
5855
        } elseif ($file_extension == "avi") {
5856
            return api_browser_support('avi');
5857
        } elseif ($file_extension == "wma") {
5858
            return api_browser_support('wma');
5859
        } elseif ($file_extension == "wmv") {
5860
            return api_browser_support('wmv');
5861
        } elseif ($file_extension == "tif" || $file_extension == "tiff") {
5862
            return api_browser_support('tif');
5863
        } elseif ($file_extension == "mov") {
5864
            return api_browser_support('mov');
5865
        } elseif ($file_extension == "au") {
5866
            return api_browser_support('au');
5867
        } elseif ($file_extension == "webm") {
5868
            return api_browser_support('webm');
5869
        }
5870
5871
        return $result;
5872
    }
5873
5874
    /**
5875
     * @param array $courseInfo
5876
     * @param int   $sessionId
5877
     *
5878
     * @return array
5879
     */
5880
    public static function getDeletedDocuments($courseInfo, $sessionId = 0)
5881
    {
5882
        $table = Database::get_course_table(TABLE_DOCUMENT);
5883
        $courseId = $courseInfo['real_id'];
5884
        $sessionCondition = api_get_session_condition($sessionId);
5885
        $sql = "SELECT * FROM $table
5886
                WHERE
5887
                  path LIKE '%DELETED%' AND
5888
                  c_id = $courseId
5889
                  $sessionCondition
5890
                ORDER BY path
5891
        ";
5892
5893
        $result = Database::query($sql);
5894
        $files = [];
5895
        while ($document = Database::fetch_array($result, 'ASSOC')) {
5896
            $files[] = $document;
5897
        }
5898
5899
        return $files;
5900
    }
5901
5902
    /**
5903
     * @param int   $id
5904
     * @param array $courseInfo
5905
     * @param int   $sessionId
5906
     *
5907
     * @return array
5908
     */
5909
    public static function getDeletedDocument($id, $courseInfo, $sessionId = 0)
5910
    {
5911
        if (empty($courseInfo)) {
5912
            return false;
5913
        }
5914
5915
        $table = Database::get_course_table(TABLE_DOCUMENT);
5916
        $courseId = $courseInfo['real_id'];
5917
        $sessionCondition = api_get_session_condition($sessionId);
5918
        $sql = "SELECT * FROM $table
5919
                WHERE
5920
                  path LIKE '%DELETED%' AND
5921
                  id = $id AND
5922
                  c_id = $courseId
5923
                  $sessionCondition
5924
                LIMIT 1
5925
        ";
5926
        $result = Database::query($sql);
5927
        if (Database::num_rows($result)) {
5928
            $result = Database::fetch_array($result, 'ASSOC');
5929
5930
            return $result;
5931
        }
5932
5933
        return [];
5934
    }
5935
5936
    /**
5937
     * @param int   $id
5938
     * @param array $courseInfo
5939
     * @param int   $sessionId
5940
     *
5941
     * @return bool
5942
     */
5943
    public static function purgeDocument($id, $courseInfo, $sessionId = 0)
5944
    {
5945
        $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
5946
        if (!empty($document)) {
5947
            $path = $document['path'];
5948
            $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
5949
            my_delete($coursePath.$path);
5950
            // Hard delete.
5951
            self::deleteDocumentFromDb($id, $courseInfo, $sessionId, true);
5952
5953
            return true;
5954
        }
5955
5956
        return false;
5957
    }
5958
5959
    /**
5960
     * @param array $courseInfo
5961
     * @param int   $sessionId
5962
     */
5963
    public static function purgeDocuments($courseInfo, $sessionId)
5964
    {
5965
        $files = self::getDeletedDocuments($courseInfo, $sessionId);
5966
        foreach ($files as $file) {
5967
            self::purgeDocument($file['id'], $courseInfo, $sessionId);
5968
        }
5969
    }
5970
5971
    /**
5972
     * @param int   $id
5973
     * @param array $courseInfo
5974
     * @param int   $sessionId
5975
     */
5976
    public static function downloadDeletedDocument($id, $courseInfo, $sessionId)
5977
    {
5978
        $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
5979
        if (!empty($document)) {
5980
            $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
5981
5982
            if (Security::check_abs_path($coursePath.$document['path'], $coursePath)) {
5983
                self::file_send_for_download($coursePath.$document['path']);
5984
                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...
5985
            }
5986
        }
5987
    }
5988
5989
    /**
5990
     * @param array $courseInfo
5991
     * @param int   $sessionId
5992
     *
5993
     * @return bool
5994
     */
5995
    public static function downloadAllDeletedDocument($courseInfo, $sessionId)
5996
    {
5997
        $files = self::getDeletedDocuments($courseInfo, $sessionId);
5998
5999
        if (empty($files)) {
6000
            return false;
6001
        }
6002
6003
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
6004
6005
        // Creating a ZIP file.
6006
        $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
6007
        $zip = new PclZip($tempZipFile);
6008
        foreach ($files as $file) {
6009
            $zip->add(
6010
                $coursePath.$file['path'],
6011
                PCLZIP_OPT_REMOVE_PATH,
6012
                $coursePath
6013
            );
6014
        }
6015
6016
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
6017
            self::file_send_for_download($tempZipFile, true);
6018
            @unlink($tempZipFile);
6019
            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...
6020
        }
6021
    }
6022
6023
    /**
6024
     * Delete documents from a session in a course.
6025
     *
6026
     * @param array $courseInfo
6027
     * @param int   $sessionId
6028
     *
6029
     * @return bool
6030
     */
6031
    public static function deleteDocumentsFromSession($courseInfo, $sessionId)
6032
    {
6033
        if (empty($courseInfo)) {
6034
            return false;
6035
        }
6036
6037
        if (empty($sessionId)) {
6038
            return false;
6039
        }
6040
6041
        $itemPropertyTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
6042
        $documentTable = Database::get_course_table(TABLE_DOCUMENT);
6043
6044
        $conditionSession = api_get_session_condition($sessionId, true, false, 'd.session_id');
6045
        $courseId = $courseInfo['real_id'];
6046
6047
        // get invisible folders
6048
        $sql = "SELECT DISTINCT d.id, path
6049
                FROM $itemPropertyTable i
6050
                INNER JOIN $documentTable d
6051
                ON (i.c_id = d.c_id)
6052
                WHERE
6053
                    d.id = i.ref AND
6054
                    i.tool = '".TOOL_DOCUMENT."'
6055
                    $conditionSession AND
6056
                    i.c_id = $courseId AND
6057
                    d.c_id = $courseId ";
6058
6059
        $result = Database::query($sql);
6060
        $documents = Database::store_result($result, 'ASSOC');
6061
        if ($documents) {
6062
            $course_dir = $courseInfo['directory'].'/document';
6063
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
6064
            $base_work_dir = $sys_course_path.$course_dir;
6065
6066
            foreach ($documents as $document) {
6067
                $documentId = $document['id'];
6068
                self::delete_document(
6069
                    $courseInfo,
6070
                    null,
6071
                    $base_work_dir,
6072
                    $sessionId,
6073
                    $documentId
6074
                );
6075
            }
6076
        }
6077
6078
        $sql = "DELETE FROM $documentTable
6079
                WHERE c_id = $courseId AND session_id = $sessionId";
6080
        Database::query($sql);
6081
6082
        $sql = "DELETE FROM $itemPropertyTable
6083
                WHERE c_id = $courseId AND session_id = $sessionId AND tool = '".TOOL_DOCUMENT."'";
6084
        Database::query($sql);
6085
    }
6086
6087
    /**
6088
     * Update the file or directory path in the document db document table.
6089
     *
6090
     * @author - Hugues Peeters <[email protected]>
6091
     *
6092
     * @param string $action   - action type require : 'delete' or 'update'
6093
     * @param string $old_path - old path info stored to change
6094
     * @param string $new_path - new path info to substitute
6095
     *
6096
     * @desc Update the file or directory path in the document db document table
6097
     */
6098
    public static function updateDbInfo($action, $old_path, $new_path = '')
6099
    {
6100
        $dbTable = Database::get_course_table(TABLE_DOCUMENT);
6101
        $course_id = api_get_course_int_id();
6102
        $old_path = Database::escape_string($old_path);
6103
        switch ($action) {
6104
            case 'delete':
6105
                $query = "DELETE FROM $dbTable
6106
                          WHERE
6107
                            c_id = $course_id AND
6108
                            (
6109
                                path LIKE BINARY '".$old_path."' OR
6110
                                path LIKE BINARY '".$old_path."/%'
6111
                            )";
6112
                Database::query($query);
6113
                break;
6114
            case 'update':
6115
                if ($new_path[0] == '.') {
6116
                    $new_path = substr($new_path, 1);
6117
                }
6118
                $new_path = str_replace('//', '/', $new_path);
6119
6120
                // Attempt to update	- tested & working for root	dir
6121
                $new_path = Database::escape_string($new_path);
6122
                $query = "UPDATE $dbTable SET
6123
                            path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
6124
                          WHERE 
6125
                                c_id = $course_id AND 
6126
                                (path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%')";
6127
                Database::query($query);
6128
                break;
6129
        }
6130
    }
6131
6132
    /**
6133
     * This function calculates the resized width and resized heigt
6134
     * according to the source and target widths
6135
     * and heights, height so that no distortions occur
6136
     * parameters.
6137
     *
6138
     * @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...
6139
     * @param $target_width = how large do you want your resized image
6140
     * @param $target_height = how large do you want your resized image
6141
     * @param $slideshow (default=0) =
6142
     *      indicates weither we are generating images for a slideshow or not,
6143
     *		this overrides the $_SESSION["image_resizing"] a bit so that a thumbnail
6144
     *	    view is also possible when you choose not to resize the source images
6145
     *
6146
     * @return array
6147
     */
6148
    public static function resizeImageSlideShow(
6149
        $image,
6150
        $target_width,
6151
        $target_height,
6152
        $slideshow = 0
6153
    ) {
6154
        // Modifications by Ivan Tcholakov, 04-MAY-2009.
6155
        $result = [];
6156
        $imageResize = Session::read('image_resizing');
6157
        if ($imageResize == 'resizing' || $slideshow == 1) {
6158
            $new_sizes = api_resize_image($image, $target_width, $target_height);
6159
            $result[] = $new_sizes['height'];
6160
            $result[] = $new_sizes['width'];
6161
        } else {
6162
            $size = api_getimagesize($image);
6163
            $result[] = $size['height'];
6164
            $result[] = $size['width'];
6165
        }
6166
6167
        return $result;
6168
    }
6169
6170
    /**
6171
     * Calculates the total size of a directory by adding the sizes (that
6172
     * are stored in the database) of all files & folders in this directory.
6173
     *
6174
     * @param string $path
6175
     * @param bool   $can_see_invisible
6176
     *
6177
     * @return int Total size
6178
     */
6179
    public static function getTotalFolderSize($path, $can_see_invisible = false)
6180
    {
6181
        $table_itemproperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6182
        $table_document = Database::get_course_table(TABLE_DOCUMENT);
6183
        $tool_document = TOOL_DOCUMENT;
6184
6185
        $course_id = api_get_course_int_id();
6186
        $session_id = api_get_session_id();
6187
        $session_condition = api_get_session_condition(
6188
            $session_id,
6189
            true,
6190
            true,
6191
            'props.session_id'
6192
        );
6193
6194
        if (empty($course_id)) {
6195
            return 0;
6196
        }
6197
6198
        $path = Database::escape_string($path);
6199
        $visibility_rule = ' props.visibility '.($can_see_invisible ? '<> 2' : '= 1');
6200
6201
        $sql = "SELECT SUM(table1.size) FROM (
6202
                SELECT props.ref, size
6203
                FROM $table_itemproperty AS props 
6204
                INNER JOIN $table_document AS docs
6205
                ON (docs.id = props.ref AND docs.c_id = props.c_id)
6206
                WHERE
6207
                    docs.c_id = $course_id AND                    
6208
                    docs.path LIKE '$path/%' AND
6209
                    props.c_id = $course_id AND
6210
                    props.tool = '$tool_document' AND
6211
                    $visibility_rule
6212
                    $session_condition
6213
                GROUP BY ref
6214
            ) as table1";
6215
6216
        $result = Database::query($sql);
6217
        if ($result && Database::num_rows($result) != 0) {
6218
            $row = Database::fetch_row($result);
6219
6220
            return $row[0] == null ? 0 : $row[0];
6221
        } else {
6222
            return 0;
6223
        }
6224
    }
6225
6226
    /**
6227
     * Adds a cloud link to the database.
6228
     *
6229
     * @author - Aquilino Blanco Cores <[email protected]>
6230
     *
6231
     * @param array  $_course
6232
     * @param string $path
6233
     * @param string $url
6234
     * @param string $name
6235
     *
6236
     * @return int id of document or 0 if already exists or there was a problem creating it
6237
     */
6238
    public static function addCloudLink($_course, $path, $url, $name)
6239
    {
6240
        $file_path = $path;
6241
        if (!self::cloudLinkExists($_course, $path, $url)) {
6242
            $doc_id = add_document($_course, $file_path, 'link', 0, $name, $url);
6243
            if ($doc_id) {
6244
                // Update document item_property
6245
                api_item_property_update(
6246
                    $_course,
6247
                    TOOL_DOCUMENT,
6248
                    $doc_id,
6249
                    'DocumentAdded',
6250
                    api_get_user_id(),
6251
                    api_get_group_id(),
6252
                    api_get_user_id(),
6253
                    null,
6254
                    null,
6255
                    api_get_session_id()
6256
                );
6257
            }
6258
6259
            // If the file is in a folder, we need to update all parent folders
6260
            item_property_update_on_folder($_course, $file_path, api_get_user_id());
6261
6262
            return $doc_id;
6263
        } else {
6264
            return 0;
6265
        }
6266
    }
6267
6268
    /**
6269
     * Deletes a cloud link from the database.
6270
     *
6271
     * @author - Aquilino Blanco Cores <[email protected]>
6272
     *
6273
     * @param array  $courseInfo
6274
     * @param string $documentId
6275
     *
6276
     * @return bool true if success / false if an error occurred
6277
     */
6278
    public static function deleteCloudLink($courseInfo, $documentId)
6279
    {
6280
        if (empty($documentId) || empty($courseInfo)) {
6281
            return false;
6282
        }
6283
6284
        $documentId = (int) $documentId;
6285
        $fileDeletedFromDb = false;
6286
        if (!empty($documentId)) {
6287
            self::deleteDocumentFromDb($documentId, $courseInfo, 0, true);
6288
            // checking
6289
            $table = Database::get_course_table(TABLE_DOCUMENT);
6290
            $courseId = $courseInfo['real_id'];
6291
            echo $sql = "SELECT * FROM $table WHERE id = $documentId AND c_id = $courseId";
6292
            $result = Database::query($sql);
6293
            $exists = Database::num_rows($result) > 0;
6294
            $fileDeletedFromDb = !$exists;
6295
        }
6296
6297
        return $fileDeletedFromDb;
6298
    }
6299
6300
    /**
6301
     * Gets the id of a cloud link with a given path.
6302
     *
6303
     * @author - Aquilino Blanco Cores <[email protected]>
6304
     *
6305
     * @param array  $courseInfo
6306
     * @param string $path
6307
     * @param string $url
6308
     *
6309
     * @return int link's id / false if no link found
6310
     */
6311
    public static function getCloudLinkId($courseInfo, $path, $url)
6312
    {
6313
        $table = Database::get_course_table(TABLE_DOCUMENT);
6314
6315
        if (empty($courseInfo)) {
6316
            return false;
6317
        }
6318
6319
        $courseId = (int) $courseInfo['real_id'];
6320
        $path = Database::escape_string($path);
6321
6322
        if (substr($path, -1) != '/') {
6323
            // Add final slash to path if not present
6324
            $path .= '/';
6325
        }
6326
6327
        if (!empty($courseId) && !empty($path)) {
6328
            $sql = "SELECT id FROM $table 
6329
                    WHERE 
6330
                        c_id = $courseId AND 
6331
                        path LIKE BINARY '$path' AND 
6332
                        comment = '$url' AND 
6333
                        filetype = 'link' 
6334
                    LIMIT 1";
6335
            $result = Database::query($sql);
6336
            if ($result && Database::num_rows($result)) {
6337
                $row = Database::fetch_array($result);
6338
6339
                return intval($row[0]);
6340
            }
6341
        }
6342
6343
        return false;
6344
    }
6345
6346
    /**
6347
     * Checks if a cloud link exists.
6348
     *
6349
     * @author - Aquilino Blanco Cores <[email protected]>
6350
     *
6351
     * @param array  $courseInfo
6352
     * @param string $path
6353
     * @param string $url
6354
     *
6355
     * @return bool true if it exists false in other case
6356
     */
6357
    public static function cloudLinkExists($courseInfo, $path, $url)
6358
    {
6359
        $exists = self::getCloudLinkId($courseInfo, $path, $url);
6360
6361
        return $exists;
6362
    }
6363
6364
    /**
6365
     * Gets the wellformed URLs regular expression in order to use it on forms' verifications.
6366
     *
6367
     * @author Aquilino Blanco Cores <[email protected]>
6368
     *
6369
     * @return string the well formed URLs regular expressions string
6370
     */
6371
    public static function getWellFormedUrlRegex()
6372
    {
6373
        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';
6374
    }
6375
6376
    /**
6377
     * Gets the files hosting sites' whitelist.
6378
     *
6379
     * @author Aquilino Blanco Cores <[email protected]>
6380
     *
6381
     * @return array the sites list
6382
     */
6383
    public static function getFileHostingWhiteList()
6384
    {
6385
        return [
6386
            'asuswebstorage.com',
6387
            'dropbox.com',
6388
            'dropboxusercontent.com',
6389
            'fileserve.com',
6390
            'drive.google.com',
6391
            'icloud.com',
6392
            'mediafire.com',
6393
            'mega.nz',
6394
            'onedrive.live.com',
6395
            'slideshare.net',
6396
            'scribd.com',
6397
            'wetransfer.com',
6398
            'box.com',
6399
            'livefilestore.com', // OneDrive
6400
        ];
6401
    }
6402
6403
    /**
6404
     * @param int $userId
6405
     *
6406
     * @return array Example [ 0 => ['code' => 'ABC', 'directory' => 'ABC0', 'path' => '/images/gallery/test.png', 'code_path' => 'ABC:/images/gallery/test.png'], 1 => ...]
6407
     */
6408
    public static function getAllDocumentsCreatedByUser($userId)
6409
    {
6410
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6411
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
6412
        $tblCourse = Database::get_main_table(TABLE_MAIN_COURSE);
6413
        $userId = (int) $userId;
6414
6415
        $sql = "SELECT DISTINCT c.code, c.directory, docs.path
6416
                FROM $tblItemProperty AS last
6417
                INNER JOIN $tblDocument AS docs
6418
                ON (
6419
                    docs.id = last.ref AND
6420
                    docs.c_id = last.c_id AND
6421
                    docs.filetype <> 'folder'
6422
                )
6423
                INNER JOIN $tblCourse as c
6424
                ON (
6425
                    docs.c_id = c.id
6426
                )
6427
                WHERE                                
6428
                    last.tool = '".TOOL_DOCUMENT."' AND   
6429
                    last.insert_user_id = $userId AND
6430
                    docs.path NOT LIKE '%_DELETED_%'                     
6431
                ORDER BY c.directory, docs.path
6432
                ";
6433
        $result = Database::query($sql);
6434
6435
        $list = [];
6436
        if (Database::num_rows($result) != 0) {
6437
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6438
                $row['code_path'] = $row['code'].':'.$row['path'];
6439
                $list[] = $row;
6440
            }
6441
        }
6442
6443
        return $list;
6444
    }
6445
6446
    /**
6447
     * Parse file information into a link.
6448
     *
6449
     * @param array  $userInfo        Current user info
6450
     * @param array  $course_info
6451
     * @param int    $session_id
6452
     * @param array  $resource
6453
     * @param int    $lp_id
6454
     * @param bool   $add_move_button
6455
     * @param string $target
6456
     * @param string $overwrite_url
6457
     *
6458
     * @return null|string
6459
     */
6460
    private static function parseFile(
6461
        $userInfo,
6462
        $course_info,
6463
        $session_id,
6464
        $resource,
6465
        $lp_id,
6466
        $add_move_button,
6467
        $target,
6468
        $overwrite_url
6469
    ) {
6470
        $img_sys_path = api_get_path(SYS_CODE_PATH).'img/';
6471
        $web_code_path = api_get_path(WEB_CODE_PATH);
6472
6473
        $documentId = $resource['id'];
6474
        $path = $resource['path'];
6475
6476
        if (empty($path)) {
6477
            $num = 0;
6478
        } else {
6479
            $num = substr_count($path, '/') - 1;
6480
        }
6481
6482
        // It's a file.
6483
        $icon = choose_image($path);
6484
        $position = strrpos($icon, '.');
6485
        $icon = substr($icon, 0, $position).'_small.gif';
6486
        $my_file_title = $resource['title'];
6487
        $visibility = $resource['visibility'];
6488
6489
        // If title is empty we try to use the path
6490
        if (empty($my_file_title)) {
6491
            $my_file_title = basename($path);
6492
        }
6493
6494
        // Show the "image name" not the filename of the image.
6495
        if ($lp_id) {
6496
            // LP URL
6497
            $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;
6498
            if (!empty($overwrite_url)) {
6499
                $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId.'';
6500
            }
6501
        } else {
6502
            // Direct document URL
6503
            $url = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6504
            if (!empty($overwrite_url)) {
6505
                $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId;
6506
            }
6507
        }
6508
6509
        $img = Display::returnIconPath($icon);
6510
        if (!file_exists($img_sys_path.$icon)) {
6511
            $img = Display::returnIconPath('default_small.gif');
6512
        }
6513
6514
        $link = Display::url(
6515
            '<img alt="" src="'.$img.'" title="" />&nbsp;'.$my_file_title,
6516
            $url,
6517
            ['target' => $target, 'class' => 'moved']
6518
        );
6519
6520
        $directUrl = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6521
        $link .= '&nbsp;'.Display::url(
6522
            Display::return_icon('preview_view.png', get_lang('Preview')),
6523
            $directUrl,
6524
            ['target' => '_blank']
6525
        );
6526
6527
        $visibilityClass = null;
6528
        if ($visibility == 0) {
6529
            $visibilityClass = ' text-muted ';
6530
        }
6531
        $return = null;
6532
6533
        if ($lp_id == false) {
6534
            $return .= '<li class="doc_resource '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6535
        } else {
6536
            $return .= '<li class="doc_resource lp_resource_element '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6537
        }
6538
6539
        $return .= '<div class="item_data" style="margin-left:'.($num * 5).'px;margin-right:5px;">';
6540
        if ($add_move_button) {
6541
            $return .= '<a class="moved" href="#">';
6542
            $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), [], ICON_SIZE_TINY);
6543
            $return .= '</a> ';
6544
        }
6545
        $return .= $link;
6546
        $sessionStar = api_get_session_image($resource['session_id'], $userInfo['status']);
6547
        $return .= $sessionStar;
6548
6549
        $return .= '</div></li>';
6550
6551
        return $return;
6552
    }
6553
6554
    /**
6555
     * @param int   $folderId
6556
     * @param array $resource
6557
     * @param int   $lp_id
6558
     *
6559
     * @return null|string
6560
     */
6561
    private static function parseFolder($folderId, $resource, $lp_id)
6562
    {
6563
        $title = isset($resource['title']) ? $resource['title'] : null;
6564
        $path = isset($resource['path']) ? $resource['path'] : null;
6565
6566
        if (empty($path)) {
6567
            $num = 0;
6568
        } else {
6569
            $num = substr_count($path, '/');
6570
        }
6571
6572
        // It's a folder.
6573
        //hide some folders
6574
        if (in_array(
6575
            $path,
6576
            ['shared_folder', 'chat_files', 'HotPotatoes_files', 'css', 'certificates']
6577
        )) {
6578
            return null;
6579
        } elseif (preg_match('/_groupdocs/', $path)) {
6580
            return null;
6581
        } elseif (preg_match('/sf_user_/', $path)) {
6582
            return null;
6583
        } elseif (preg_match('/shared_folder_session_/', $path)) {
6584
            return null;
6585
        }
6586
6587
        $onclick = '';
6588
        // if in LP, hidden folder are displayed in grey
6589
        $folder_class_hidden = '';
6590
        if ($lp_id) {
6591
            if (isset($resource['visible']) && $resource['visible'] == 0) {
6592
                $folder_class_hidden = "doc_folder_hidden"; // in base.css
6593
            }
6594
            $onclick = 'onclick="javascript: testResources(\'res_'.$resource['id'].'\',\'img_'.$resource['id'].'\')"';
6595
        }
6596
        $return = null;
6597
6598
        if (empty($path)) {
6599
            $return = '<ul class="lp_resource">';
6600
        }
6601
6602
        $return .= '<li class="doc_folder '.$folder_class_hidden.'" id="doc_id_'.$resource['id'].'"  style="margin-left:'.($num * 18).'px; ">';
6603
6604
        $image = Display::returnIconPath('nolines_plus.gif');
6605
        if (empty($path)) {
6606
            $image = Display::returnIconPath('nolines_minus.gif');
6607
        }
6608
        $return .= '<img style="cursor: pointer;" src="'.$image.'" align="absmiddle" id="img_'.$resource['id'].'" '.$onclick.'>';
6609
        $return .= Display::return_icon('lp_folder.gif').'&nbsp;';
6610
        $return .= '<span '.$onclick.' style="cursor: pointer;" >'.$title.'</span>';
6611
        $return .= '</li>';
6612
6613
        if (empty($path)) {
6614
            if ($folderId == false) {
6615
                $return .= '<div id="res_'.$resource['id'].'" >';
6616
            } else {
6617
                $return .= '<div id="res_'.$resource['id'].'" style="display: none;" >';
6618
            }
6619
        }
6620
6621
        return $return;
6622
    }
6623
6624
    /**
6625
     * Get the button to edit document.
6626
     *
6627
     * @param bool   $isReadOnly
6628
     * @param array  $documentData
6629
     * @param string $extension
6630
     * @param bool   $isCertificateMode
6631
     *
6632
     * @return string
6633
     */
6634
    private static function getButtonEdit($isReadOnly, array $documentData, $extension, $isCertificateMode)
6635
    {
6636
        $extension = strtolower($extension);
6637
        $iconEn = Display::return_icon('edit.png', get_lang('Modify'));
6638
        $iconDis = Display::return_icon('edit_na.png', get_lang('Modify'));
6639
        $courseParams = api_get_cidreq();
6640
        $webOdfExtensionList = self::get_web_odf_extension_list();
6641
        $path = $documentData['path'];
6642
        $document_id = $documentData['id'];
6643
6644
        if ($isReadOnly) {
6645
            if (!api_is_course_admin() && !api_is_platform_admin()) {
6646
                return $iconDis;
6647
            }
6648
6649
            if (
6650
                $extension == 'svg' && api_browser_support('svg') &&
6651
                api_get_setting('enabled_support_svg') == 'true'
6652
            ) {
6653
                return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
6654
            }
6655
6656
            if (
6657
                in_array($extension, $webOdfExtensionList) &&
6658
                api_get_configuration_value('enabled_support_odf') === true
6659
            ) {
6660
                return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
6661
            }
6662
6663
            if (
6664
                in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6665
                    api_get_setting('enabled_support_pixlr') == 'true'
6666
            ) {
6667
                return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
6668
            }
6669
6670
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
6671
        }
6672
6673
        if (in_array($path, self::get_system_folders())) {
6674
            return $iconDis;
6675
        }
6676
6677
        if ($isCertificateMode) {
6678
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id&curdirpath=/certificates");
6679
        }
6680
6681
        $sessionId = api_get_session_id();
6682
6683
        if ($sessionId && $documentData['session_id'] != $sessionId) {
6684
            return $iconDis;
6685
        }
6686
6687
        if (
6688
            $extension == 'svg' && api_browser_support('svg') &&
6689
            api_get_setting('enabled_support_svg') == 'true'
6690
        ) {
6691
            return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
6692
        }
6693
6694
        if (
6695
            in_array($extension, $webOdfExtensionList) &&
6696
            api_get_configuration_value('enabled_support_odf') === true
6697
        ) {
6698
            return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
6699
        }
6700
6701
        if (
6702
            in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6703
                api_get_setting('enabled_support_pixlr') == 'true'
6704
        ) {
6705
            return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
6706
        }
6707
6708
        return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
6709
    }
6710
6711
    /**
6712
     * Get the button to move document.
6713
     *
6714
     * @param bool  $isReadOnly
6715
     * @param array $documentData
6716
     * @param bool  $isCertificateMode
6717
     * @param int   $parentId
6718
     *
6719
     * @return string
6720
     */
6721
    private static function getButtonMove($isReadOnly, array $documentData, $isCertificateMode, $parentId)
6722
    {
6723
        $iconEn = Display::return_icon('move.png', get_lang('Move'));
6724
        $iconDis = Display::return_icon('move_na.png', get_lang('Move'));
6725
6726
        if ($isReadOnly) {
6727
            return $iconDis;
6728
        }
6729
6730
        $path = $documentData['path'];
6731
        $document_id = $documentData['id'];
6732
        $sessionId = api_get_session_id();
6733
        $courseParams = api_get_cidreq();
6734
6735
        if ($isCertificateMode || in_array($path, self::get_system_folders())) {
6736
            return $iconDis;
6737
        }
6738
6739
        if ($sessionId) {
6740
            if ($documentData['session_id'] != $sessionId) {
6741
                return $iconDis;
6742
            }
6743
        }
6744
6745
        $urlMoveParams = http_build_query(['id' => $parentId, 'move' => $document_id]);
6746
6747
        return Display::url(
6748
            $iconEn,
6749
            api_get_self()."?$courseParams&$urlMoveParams"
6750
        );
6751
    }
6752
6753
    /**
6754
     * Get the button to set visibility to document.
6755
     *
6756
     * @param bool  $isReadOnly
6757
     * @param int   $visibility
6758
     * @param array $documentData
6759
     * @param bool  $isCertificateMode
6760
     * @param int   $parentId
6761
     *
6762
     * @return null|string
6763
     */
6764
    private static function getButtonVisibility(
6765
        $isReadOnly,
6766
        $visibility,
6767
        array $documentData,
6768
        $isCertificateMode,
6769
        $parentId
6770
    ) {
6771
        $visibility_icon = $visibility == 0 ? 'invisible' : 'visible';
6772
        $visibility_command = $visibility == 0 ? 'set_visible' : 'set_invisible';
6773
        $courseParams = api_get_cidreq();
6774
6775
        if ($isReadOnly) {
6776
            if (api_is_allowed_to_edit() || api_is_platform_admin()) {
6777
                return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
6778
            }
6779
6780
            return null;
6781
        }
6782
6783
        if ($isCertificateMode) {
6784
            return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
6785
        }
6786
6787
        if (api_is_allowed_to_edit() || api_is_platform_admin()) {
6788
            $tip_visibility = $visibility_icon == 'invisible' ? get_lang('Show') : get_lang('Hide');
6789
6790
            return Display::url(
6791
                Display::return_icon($visibility_icon.'.png', $tip_visibility),
6792
                api_get_self()."?$courseParams&id=$parentId&$visibility_command={$documentData['id']}"
6793
            );
6794
        }
6795
6796
        return null;
6797
    }
6798
6799
    /**
6800
     * GEt the button to delete a document.
6801
     *
6802
     * @param bool   $isReadOnly
6803
     * @param array  $documentData
6804
     * @param bool   $isCertificateMode
6805
     * @param string $curDirPath
6806
     * @param int    $parentId
6807
     *
6808
     * @return string
6809
     */
6810
    private static function getButtonDelete(
6811
        $isReadOnly,
6812
        array $documentData,
6813
        $isCertificateMode,
6814
        $curDirPath,
6815
        $parentId
6816
    ) {
6817
        $iconEn = Display::return_icon('delete.png', get_lang('Delete'));
6818
        $iconDis = Display::return_icon('delete_na.png', get_lang('ThisFolderCannotBeDeleted'));
6819
        $path = $documentData['path'];
6820
        $id = $documentData['id'];
6821
        $courseParams = api_get_cidreq();
6822
6823
        if ($isReadOnly) {
6824
            return $iconDis;
6825
        }
6826
6827
        if (in_array($path, self::get_system_folders())) {
6828
            return $iconDis;
6829
        }
6830
6831
        $titleToShow = addslashes(basename($documentData['title']));
6832
        $urlDeleteParams = http_build_query([
6833
            'curdirpath' => $curDirPath,
6834
            'action' => 'delete_item',
6835
            'id' => $parentId,
6836
            'deleteid' => $documentData['id'],
6837
        ]);
6838
6839
        $btn = Display::url(
6840
            $iconEn,
6841
            '#',
6842
            [
6843
                'data-item-title' => $titleToShow,
6844
                'data-href' => api_get_self()."?$courseParams&$urlDeleteParams",
6845
                'data-toggle' => 'modal',
6846
                'data-target' => '#confirm-delete',
6847
            ]
6848
        );
6849
6850
        if (
6851
            isset($_GET['curdirpath']) &&
6852
            $_GET['curdirpath'] == '/certificates' &&
6853
            self::get_default_certificate_id(api_get_course_id()) == $id
6854
        ) {
6855
            return $btn;
6856
        }
6857
6858
        if ($isCertificateMode) {
6859
            return $btn;
6860
        }
6861
6862
        $sessionId = api_get_session_id();
6863
6864
        if ($sessionId) {
6865
            if ($documentData['session_id'] != $sessionId) {
6866
                return $iconDis;
6867
            }
6868
        }
6869
6870
        return $btn;
6871
    }
6872
}
6873