Completed
Push — master ( ae5621...ef667c )
by Julito
13:23
created

DocumentManager::fixDocumentName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 5
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
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/mpeg4-generic',
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[sizeof($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
        //else return octet-stream
277
        return 'application/octet-stream';
278
    }
279
280
    /**
281
     * This function streams a file to the client.
282
     *
283
     * @param string $full_file_name
284
     * @param bool   $forced
285
     * @param string $name
286
     * @param bool   $fixLinksHttpToHttps change file content from http to https
287
     *
288
     * @return false if file doesn't exist, true if stream succeeded
289
     */
290
    public static function file_send_for_download(
291
        $full_file_name,
292
        $forced = false,
293
        $name = '',
294
        $fixLinksHttpToHttps = false
295
    ) {
296
        session_write_close(); //we do not need write access to session anymore
297
        if (!is_file($full_file_name)) {
298
            return false;
299
        }
300
        $filename = $name == '' ? basename($full_file_name) : api_replace_dangerous_char($name);
301
        $len = filesize($full_file_name);
302
        // Fixing error when file name contains a ","
303
        $filename = str_replace(',', '', $filename);
304
        $sendFileHeaders = api_get_configuration_value('enable_x_sendfile_headers');
305
306
        // Allows chrome to make videos and audios seekable
307
        header('Accept-Ranges: bytes');
308
309
        if ($forced) {
310
            // Force the browser to save the file instead of opening it
311
            if (isset($sendFileHeaders) &&
312
                !empty($sendFileHeaders)) {
313
                header("X-Sendfile: $filename");
314
            }
315
316
            header('Content-type: application/octet-stream');
317
            header('Content-length: '.$len);
318
            if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
319
                header('Content-Disposition: filename= '.$filename);
320
            } else {
321
                header('Content-Disposition: attachment; filename= '.$filename);
322
            }
323
            if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
324
                header('Pragma: ');
325
                header('Cache-Control: ');
326
                header('Cache-Control: public'); // IE cannot download from sessions without a cache
327
            }
328
            header('Content-Description: '.$filename);
329
            header('Content-Transfer-Encoding: binary');
330
331
            if (function_exists('ob_end_clean') && ob_get_length()) {
332
                // Use ob_end_clean() to avoid weird buffering situations
333
                // where file is sent broken/incomplete for download
334
                ob_end_clean();
335
            }
336
337
            $res = fopen($full_file_name, 'r');
338
            fpassthru($res);
339
340
            return true;
341
        } else {
342
            // no forced download, just let the browser decide what to do according to the mimetype
343
            $lpFixedEncoding = api_get_configuration_value('lp_fixed_encoding');
344
345
            // Commented to let courses content to be cached in order to improve performance:
346
            //header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
347
            //header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
348
349
            // Commented to avoid double caching declaration when playing with IE and HTTPS
350
            //header('Cache-Control: no-cache, must-revalidate');
351
            //header('Pragma: no-cache');
352
            $contentType = self::file_get_mime_type($filename);
353
            switch ($contentType) {
354
                case 'text/html':
355
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
356
                        $contentType .= '; charset=UTF-8';
357
                    } else {
358
                        $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
359
                        if (!empty($encoding)) {
360
                            $contentType .= '; charset='.$encoding;
361
                        }
362
                    }
363
                    break;
364
                case 'text/plain':
365
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
366
                        $contentType .= '; charset=UTF-8';
367
                    } else {
368
                        $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
369
                        if (!empty($encoding)) {
370
                            $contentType .= '; charset='.$encoding;
371
                        }
372
                    }
373
                    break;
374
                case 'application/vnd.dwg':
375
                case 'application/vnd.dwf':
376
                    header('Content-type: application/octet-stream');
377
                    break;
378
            }
379
380
            header('Content-type: '.$contentType);
381
            header('Content-Length: '.$len);
382
            $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
383
            if (strpos($user_agent, 'msie')) {
384
                header('Content-Disposition: ; filename= '.$filename);
385
            } else {
386
                header('Content-Disposition: inline; filename= '.$filename);
387
            }
388
389
            if ($fixLinksHttpToHttps) {
390
                $content = file_get_contents($full_file_name);
391
                $content = str_replace(
392
                    ['http%3A%2F%2F', 'http://'],
393
                    ['https%3A%2F%2F', 'https://'],
394
                    $content
395
                );
396
                echo $content;
397
            } else {
398
                if (function_exists('ob_end_clean') && ob_get_length()) {
399
                    // Use ob_end_clean() to avoid weird buffering situations
400
                    // where file is sent broken/incomplete for download
401
                    ob_end_clean();
402
                }
403
404
                readfile($full_file_name);
405
            }
406
407
            return true;
408
        }
409
    }
410
411
    /**
412
     * Session folder filters.
413
     *
414
     * @param string $path
415
     * @param int    $sessionId
416
     *
417
     * @return null|string
418
     */
419
    public static function getSessionFolderFilters($path, $sessionId)
420
    {
421
        $sessionId = intval($sessionId);
422
        $condition = null;
423
424
        if (!empty($sessionId)) {
425
            // Chat folder filter
426
            if ($path == '/chat_files') {
427
                $condition .= " AND (docs.session_id = '$sessionId') ";
428
            }
429
            // share_folder filter
430
            $condition .= " AND docs.path != '/shared_folder' ";
431
        }
432
433
        return $condition;
434
    }
435
436
    /**
437
     * Fetches all document data for the given user/group.
438
     *
439
     * @param array  $courseInfo
440
     * @param string $path
441
     * @param int    $toGroupId       iid
442
     * @param int    $toUserId
443
     * @param bool   $canSeeInvisible
444
     * @param bool   $search
445
     * @param int    $sessionId
446
     *
447
     * @return array with all document data
448
     */
449
    public static function getAllDocumentData(
450
        $courseInfo,
451
        $path = '/',
452
        $toGroupId = 0,
453
        $toUserId = null,
454
        $canSeeInvisible = false,
455
        $search = false,
456
        $sessionId = 0
457
    ) {
458
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
459
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
460
461
        $userGroupFilter = '';
462
        if (!is_null($toUserId)) {
463
            $toUserId = intval($toUserId);
464
            $userGroupFilter = "last.to_user_id = $toUserId";
465
            if (empty($toUserId)) {
466
                $userGroupFilter = " (last.to_user_id = 0 OR last.to_user_id IS NULL) ";
467
            }
468
        } else {
469
            $toGroupId = intval($toGroupId);
470
            $userGroupFilter = "last.to_group_id = $toGroupId";
471
            if (empty($toGroupId)) {
472
                $userGroupFilter = "( last.to_group_id = 0 OR last.to_group_id IS NULL) ";
473
            }
474
        }
475
476
        // Escape underscores in the path so they don't act as a wildcard
477
        $originalPath = $path;
478
        $path = str_replace('_', '\_', $path);
479
480
        $visibilityBit = ' <> 2';
481
482
        // The given path will not end with a slash, unless it's the root '/'
483
        // so no root -> add slash
484
        $addedSlash = $path == '/' ? '' : '/';
485
486
        // Condition for the session
487
        $sessionId = $sessionId ?: api_get_session_id();
488
        $conditionSession = " AND (last.session_id = '$sessionId' OR (last.session_id = '0' OR last.session_id IS NULL) )";
489
        $conditionSession .= self::getSessionFolderFilters($originalPath, $sessionId);
490
491
        $sharedCondition = null;
492
        if ($originalPath == '/shared_folder') {
493
            $students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
494
            if (!empty($students)) {
495
                $conditionList = [];
496
                foreach ($students as $studentInfo) {
497
                    $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
498
                }
499
                $sharedCondition .= ' AND docs.path IN ("'.implode('","', $conditionList).'")';
500
            }
501
        }
502
503
        $sql = "SELECT
504
                    docs.id,
505
                    docs.filetype,
506
                    docs.path,
507
                    docs.title,
508
                    docs.comment,
509
                    docs.size,
510
                    docs.readonly,
511
                    docs.session_id,
512
                    last.session_id item_property_session_id,
513
                    last.lastedit_date,
514
                    last.visibility,
515
                    last.insert_user_id
516
                FROM $tblItemProperty AS last
517
                INNER JOIN $tblDocument AS docs
518
                ON (
519
                    docs.id = last.ref AND
520
                    docs.c_id = last.c_id
521
                )
522
                WHERE                                
523
                    last.tool = '".TOOL_DOCUMENT."' AND 
524
                    docs.c_id = {$courseInfo['real_id']} AND
525
                    last.c_id = {$courseInfo['real_id']} AND
526
                    docs.path LIKE '".Database::escape_string($path.$addedSlash.'%')."' AND
527
                    docs.path NOT LIKE '".Database::escape_string($path.$addedSlash.'%/%')."' AND
528
                    docs.path NOT LIKE '%_DELETED_%' AND
529
                    $userGroupFilter AND
530
                    last.visibility $visibilityBit
531
                    $conditionSession
532
                    $sharedCondition
533
                ORDER BY last.iid DESC, last.session_id DESC
534
                ";
535
        $result = Database::query($sql);
536
537
        $documentData = [];
538
        $isAllowedToEdit = api_is_allowed_to_edit(null, true);
539
        $isCoach = api_is_coach();
540
        if ($result !== false && Database::num_rows($result) != 0) {
541
            $rows = [];
542
543
            $hideInvisibleDocuments = api_get_configuration_value('hide_invisible_course_documents_in_sessions');
544
545
            while ($row = Database::fetch_array($result, 'ASSOC')) {
546
                if (isset($rows[$row['id']])) {
547
                    continue;
548
                }
549
550
                // If we are in session and hide_invisible_course_documents_in_sessions is enabled
551
                // Then we avoid the documents that have visibility in session but that they come from a base course
552
                if ($hideInvisibleDocuments && $sessionId) {
553
                    if ($row['item_property_session_id'] == $sessionId && empty($row['session_id'])) {
554
                        continue;
555
                    }
556
                }
557
558
                $rows[$row['id']] = $row;
559
            }
560
561
            // If we are in session and hide_invisible_course_documents_in_sessions is enabled
562
            // Or if we are students
563
            // Then don't list the invisible or deleted documents
564
            if (($sessionId && $hideInvisibleDocuments) || (!$isCoach && !$isAllowedToEdit)) {
565
                $rows = array_filter($rows, function ($row) {
566
                    if (in_array($row['visibility'], ['0', '2'])) {
567
                        return false;
568
                    }
569
570
                    return true;
571
                });
572
            }
573
574
            foreach ($rows as $row) {
575
                if ($row['filetype'] == 'file' &&
576
                    pathinfo($row['path'], PATHINFO_EXTENSION) == 'html'
577
                ) {
578
                    // Templates management
579
                    $tblTemplate = Database::get_main_table(TABLE_MAIN_TEMPLATES);
580
                    $sql = "SELECT id FROM $tblTemplate
581
                            WHERE
582
                                course_code = '".$courseInfo['code']."' AND
583
                                user_id = '".api_get_user_id()."' AND
584
                                ref_doc = '".$row['id']."'";
585
                    $templateResult = Database::query($sql);
586
                    $row['is_template'] = (Database::num_rows($templateResult) > 0) ? 1 : 0;
587
                }
588
                $row['basename'] = basename($row['path']);
589
                // Just filling $document_data.
590
                $documentData[$row['id']] = $row;
591
            }
592
593
            // Only for the student we filter the results see BT#1652
594
            if (!$isCoach && !$isAllowedToEdit) {
595
                // Checking parents visibility.
596
                $finalDocumentData = [];
597
                foreach ($documentData as $row) {
598
                    $isVisible = self::check_visibility_tree(
599
                        $row['id'],
600
                        $courseInfo['code'],
601
                        $sessionId,
602
                        api_get_user_id(),
603
                        $toGroupId
604
                    );
605
                    if ($isVisible) {
606
                        $finalDocumentData[$row['id']] = $row;
607
                    }
608
                }
609
            } else {
610
                $finalDocumentData = $documentData;
611
            }
612
613
            return $finalDocumentData;
614
        } else {
615
            return [];
616
        }
617
    }
618
619
    /**
620
     * Gets the paths of all folders in a course
621
     * can show all folders (except for the deleted ones) or only visible ones.
622
     *
623
     * @param array  $_course
624
     * @param int    $groupIid          iid
625
     * @param bool   $can_see_invisible
626
     * @param bool   $getInvisibleList
627
     * @param string $path              current path
628
     *
629
     * @return array with paths
630
     */
631
    public static function get_all_document_folders(
632
        $_course,
633
        $groupIid = 0,
634
        $can_see_invisible = false,
635
        $getInvisibleList = false,
636
        $path = ''
637
    ) {
638
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
639
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
640
        $groupIid = intval($groupIid);
641
        $document_folders = [];
642
643
        $students = CourseManager::get_user_list_from_course_code(
644
            $_course['code'],
645
            api_get_session_id()
646
        );
647
648
        $conditionList = [];
649
        if (!empty($students)) {
650
            foreach ($students as $studentId => $studentInfo) {
651
                $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
652
            }
653
        }
654
655
        $groupCondition = " last.to_group_id = $groupIid";
656
        if (empty($groupIid)) {
657
            $groupCondition = " (last.to_group_id = 0 OR last.to_group_id IS NULL)";
658
        }
659
660
        $show_users_condition = '';
661
        if (api_get_setting('show_users_folders') === 'false') {
662
            $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
663
        }
664
665
        if ($can_see_invisible) {
666
            // condition for the session
667
            $session_id = api_get_session_id();
668
            //$condition_session = api_get_session_condition($session_id, true, false, 'docs.session_id');
669
670
            $session_id = $session_id ?: api_get_session_id();
671
            $condition_session = " AND (last.session_id = '$session_id' OR (last.session_id = '0' OR last.session_id IS NULL) )";
672
            $condition_session .= self::getSessionFolderFilters($path, $session_id);
673
674
            if ($groupIid != 0) {
675
                $sql = "SELECT DISTINCT docs.id, path
676
                       FROM $TABLE_ITEMPROPERTY  AS last
677
                       INNER JOIN $TABLE_DOCUMENT  AS docs
678
                       ON (
679
                            docs.id = last.ref AND
680
                            docs.c_id = last.c_id
681
                       )
682
                       WHERE                       
683
                            last.tool = '".TOOL_DOCUMENT."' AND
684
                            last.c_id = {$_course['real_id']} AND
685
                            docs.c_id = {$_course['real_id']} AND
686
                            docs.filetype = 'folder' AND
687
                            $groupCondition AND
688
                            docs.path NOT LIKE '%shared_folder%' AND
689
                            docs.path NOT LIKE '%_DELETED_%' AND
690
                            last.visibility <> 2                            
691
                            $condition_session ";
692
            } else {
693
                $sql = "SELECT DISTINCT docs.id, path
694
                        FROM $TABLE_ITEMPROPERTY  AS last
695
                        INNER JOIN $TABLE_DOCUMENT  AS docs
696
                        ON (
697
                            docs.id = last.ref AND
698
                            docs.c_id = last.c_id                          
699
                        )
700
                        WHERE
701
                            last.tool = '".TOOL_DOCUMENT."' AND
702
                            last.c_id = {$_course['real_id']} AND
703
                            docs.c_id = {$_course['real_id']} AND
704
                            docs.filetype = 'folder' AND
705
                            docs.path NOT LIKE '%_DELETED_%' AND
706
                            $groupCondition AND
707
                            last.visibility <> 2
708
                            $show_users_condition 
709
                            $condition_session 
710
                        ";
711
            }
712
            $result = Database::query($sql);
713
714
            if ($result && Database::num_rows($result) != 0) {
715
                while ($row = Database::fetch_array($result, 'ASSOC')) {
716
                    if (self::is_folder_to_avoid($row['path'])) {
717
                        continue;
718
                    }
719
720
                    if (strpos($row['path'], '/shared_folder/') !== false) {
721
                        if (!in_array($row['path'], $conditionList)) {
722
                            continue;
723
                        }
724
                    }
725
726
                    $document_folders[$row['id']] = $row['path'];
727
                }
728
729
                if (!empty($document_folders)) {
730
                    natsort($document_folders);
731
                }
732
733
                return $document_folders;
734
            } else {
735
                return false;
736
            }
737
        } else {
738
            // No invisible folders
739
            // Condition for the session
740
            $session_id = api_get_session_id();
741
            $condition_session = api_get_session_condition(
742
                $session_id,
743
                true,
744
                false,
745
                'docs.session_id'
746
            );
747
748
            $visibilityCondition = 'last.visibility = 1';
749
            $fileType = "docs.filetype = 'folder' AND";
750
            if ($getInvisibleList) {
751
                $visibilityCondition = 'last.visibility = 0';
752
                $fileType = '';
753
            }
754
755
            //get visible folders
756
            $sql = "SELECT DISTINCT docs.id, path
757
                    FROM
758
                    $TABLE_ITEMPROPERTY AS last 
759
                    INNER JOIN $TABLE_DOCUMENT AS docs
760
                    ON (docs.id = last.ref AND last.c_id = docs.c_id)
761
                    WHERE
762
                        $fileType
763
                        last.tool = '".TOOL_DOCUMENT."' AND
764
                        $groupCondition AND
765
                        $visibilityCondition
766
                        $show_users_condition
767
                        $condition_session AND
768
                        last.c_id = {$_course['real_id']}  AND
769
                        docs.c_id = {$_course['real_id']} ";
770
771
            $result = Database::query($sql);
772
773
            $visibleFolders = [];
774
            while ($row = Database::fetch_array($result, 'ASSOC')) {
775
                $visibleFolders[$row['id']] = $row['path'];
776
            }
777
778
            if ($getInvisibleList) {
779
                return $visibleFolders;
780
            }
781
782
            //get invisible folders
783
            $sql = "SELECT DISTINCT docs.id, path
784
                    FROM $TABLE_ITEMPROPERTY AS last 
785
                    INNER JOIN $TABLE_DOCUMENT AS docs
786
                    ON (docs.id = last.ref AND last.c_id = docs.c_id)
787
                    WHERE                        
788
                        docs.filetype = 'folder' AND
789
                        last.tool = '".TOOL_DOCUMENT."' AND
790
                        $groupCondition AND
791
                        last.visibility = 0 $condition_session AND
792
                        last.c_id = {$_course['real_id']} AND
793
                        docs.c_id = {$_course['real_id']} ";
794
            $result = Database::query($sql);
795
            $invisibleFolders = [];
796
            while ($row = Database::fetch_array($result, 'ASSOC')) {
797
                //get visible folders in the invisible ones -> they are invisible too
798
                $sql = "SELECT DISTINCT docs.id, path
799
                        FROM $TABLE_ITEMPROPERTY AS last 
800
                        INNER JOIN $TABLE_DOCUMENT AS docs
801
                        ON (docs.id = last.ref AND docs.c_id = last.c_id)
802
                        WHERE                            
803
                            docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
804
                            docs.filetype = 'folder' AND
805
                            last.tool = '".TOOL_DOCUMENT."' AND
806
                            $groupCondition AND
807
                            last.visibility = 1 $condition_session AND
808
                            last.c_id = {$_course['real_id']} AND
809
                            docs.c_id = {$_course['real_id']}  ";
810
                $folder_in_invisible_result = Database::query($sql);
811
                while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
812
                    $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
813
                }
814
            }
815
816
            // If both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
817
            if (is_array($visibleFolders) && is_array($invisibleFolders)) {
818
                $document_folders = array_diff($visibleFolders, $invisibleFolders);
819
                natsort($document_folders);
820
821
                return $document_folders;
822
            } elseif (is_array($visibleFolders)) {
823
                natsort($visibleFolders);
824
825
                return $visibleFolders;
826
            } else {
827
                //no visible folders found
828
                return false;
829
            }
830
        }
831
    }
832
833
    /**
834
     * This check if a document has the readonly property checked, then see if the user
835
     * is the owner of this file, if all this is true then return true.
836
     *
837
     * @param array  $_course
838
     * @param int    $user_id     id of the current user
839
     * @param string $file        path stored in the database (if not defined, $documentId must be used)
840
     * @param int    $document_id in case you dont have the file path ,
841
     *                            insert the id of the file here and leave $file in blank ''
842
     * @param bool   $to_delete
843
     * @param int    $sessionId
844
     *
845
     * @return bool true/false
846
     * */
847
    public static function check_readonly(
848
        $_course,
849
        $user_id,
850
        $file = null,
851
        $document_id = 0,
852
        $to_delete = false,
853
        $sessionId = null,
854
        $documentId = null
855
    ) {
856
        if (empty($sessionId)) {
857
            $sessionId = api_get_session_id();
858
        } else {
859
            $sessionId = intval($sessionId);
860
        }
861
862
        if (empty($document_id) || !is_numeric($document_id)) {
863
            $document_id = self::get_document_id($_course, $file, $sessionId);
864
        } else {
865
            $document_id = intval($document_id);
866
        }
867
868
        $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
869
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
870
        $course_id = $_course['real_id'];
871
872
        if ($to_delete) {
873
            if (self::is_folder($_course, $document_id)) {
874
                if (!empty($file)) {
875
                    $path = Database::escape_string($file);
876
                    // Check
877
                    $sql = "SELECT td.id, readonly, tp.insert_user_id
878
                            FROM $TABLE_DOCUMENT td 
879
                            INNER JOIN $TABLE_PROPERTY tp
880
                            ON (td.c_id = tp.c_id AND tp.ref= td.id)
881
                            WHERE
882
                                td.c_id = $course_id AND
883
                                tp.c_id = $course_id AND
884
                                td.session_id = $sessionId AND                                
885
                                (path='".$path."' OR path LIKE BINARY '".$path."/%' ) ";
886
                    // Get all id's of documents that are deleted
887
                    $what_to_check_result = Database::query($sql);
888
889
                    if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
890
                        // file with readonly set to 1 exist?
891
                        $readonly_set = false;
892
                        while ($row = Database::fetch_array($what_to_check_result)) {
893
                            //query to delete from item_property table
894
                            if ($row['readonly'] == 1) {
895
                                if (!($row['insert_user_id'] == $user_id)) {
896
                                    $readonly_set = true;
897
                                    break;
898
                                }
899
                            }
900
                        }
901
902
                        if ($readonly_set) {
903
                            return true;
904
                        }
905
                    }
906
                }
907
908
                return false;
909
            }
910
        }
911
912
        if (!empty($document_id)) {
913
            $sql = "SELECT a.insert_user_id, b.readonly
914
                   FROM $TABLE_PROPERTY a 
915
                   INNER JOIN $TABLE_DOCUMENT b
916
                   ON (a.c_id = b.c_id AND a.ref= b.id)
917
                   WHERE
918
            			a.c_id = $course_id AND
919
                        b.c_id = $course_id AND
920
            			a.ref = $document_id 
921
                    LIMIT 1";
922
            $result = Database::query($sql);
923
            $doc_details = Database::fetch_array($result, 'ASSOC');
924
925
            if ($doc_details['readonly'] == 1) {
926
                return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
927
            }
928
        }
929
930
        return false;
931
    }
932
933
    /**
934
     * This check if a document is a folder or not.
935
     *
936
     * @param array $_course
937
     * @param int   $id      document id
938
     *
939
     * @return bool true/false
940
     * */
941
    public static function is_folder($_course, $id)
942
    {
943
        $table = Database::get_course_table(TABLE_DOCUMENT);
944
        if (empty($_course)) {
945
            return false;
946
        }
947
        $course_id = $_course['real_id'];
948
        $id = (int) $id;
949
        $sql = "SELECT filetype FROM $table
950
                WHERE c_id = $course_id AND id= $id";
951
        $result = Database::fetch_array(Database::query($sql), 'ASSOC');
952
953
        return $result['filetype'] == 'folder';
954
    }
955
956
    /**
957
     * @param int   $document_id
958
     * @param array $course_info
959
     * @param int   $session_id
960
     * @param bool  $remove_content_from_db
961
     */
962
    public static function deleteDocumentFromDb(
963
        $document_id,
964
        $course_info = [],
965
        $session_id = 0,
966
        $remove_content_from_db = false
967
    ) {
968
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
969
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
970
971
        // Deleting from the DB
972
        $user_id = api_get_user_id();
973
        $document_id = intval($document_id);
974
975
        if (empty($course_info)) {
976
            $course_info = api_get_course_info();
977
        }
978
979
        if (empty($session_id)) {
980
            $session_id = api_get_session_id();
981
        }
982
        // Soft DB delete
983
        api_item_property_update(
984
            $course_info,
985
            TOOL_DOCUMENT,
986
            $document_id,
987
            'delete',
988
            $user_id,
989
            null,
990
            null,
991
            null,
992
            null,
993
            $session_id
994
        );
995
        self::delete_document_from_search_engine($course_info['code'], $document_id);
996
        self::unset_document_as_template($document_id, $course_info['code'], $user_id);
997
998
        //Hard DB delete
999
        if ($remove_content_from_db) {
1000
            $sql = "DELETE FROM $TABLE_ITEMPROPERTY
1001
                    WHERE
1002
                        c_id = {$course_info['real_id']} AND
1003
                        ref = ".$document_id." AND
1004
                        tool='".TOOL_DOCUMENT."'";
1005
            Database::query($sql);
1006
1007
            $sql = "DELETE FROM $TABLE_DOCUMENT
1008
                    WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
1009
            Database::query($sql);
1010
        }
1011
    }
1012
1013
    /**
1014
     * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
1015
     * Files/folders that are inside a deleted folder get visibility 2.
1016
     *
1017
     * @param array  $_course
1018
     * @param string $path          Path stored in the database
1019
     * @param string $base_work_dir Path to the documents folder (if not defined, $documentId must be used)
1020
     * @param int    $sessionId     The ID of the session, if any
1021
     * @param int    $documentId    The document id, if available
1022
     * @param int    $groupId       iid
1023
     *
1024
     * @return bool true/false
1025
     *
1026
     * @todo now only files/folders in a folder get visibility 2, we should rename them too.
1027
     * @todo We should be able to get rid of this later when using only documentId (check further usage)
1028
     */
1029
    public static function delete_document(
1030
        $_course,
1031
        $path = null,
1032
        $base_work_dir = null,
1033
        $sessionId = null,
1034
        $documentId = null,
1035
        $groupId = 0
1036
    ) {
1037
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1038
1039
        $groupId = intval($groupId);
1040
        if (empty($groupId)) {
1041
            $groupId = api_get_group_id();
1042
        }
1043
1044
        $sessionId = intval($sessionId);
1045
        if (empty($sessionId)) {
1046
            $sessionId = api_get_session_id();
1047
        }
1048
1049
        $course_id = $_course['real_id'];
1050
1051
        if (empty($course_id)) {
1052
            return false;
1053
        }
1054
1055
        if (empty($base_work_dir)) {
1056
            return false;
1057
        }
1058
1059
        if (empty($documentId)) {
1060
            $documentId = self::get_document_id($_course, $path, $sessionId);
1061
            $docInfo = self::get_document_data_by_id(
1062
                $documentId,
1063
                $_course['code'],
1064
                false,
1065
                $sessionId
1066
            );
1067
            $path = $docInfo['path'];
1068
        } else {
1069
            $docInfo = self::get_document_data_by_id(
1070
                $documentId,
1071
                $_course['code'],
1072
                false,
1073
                $sessionId
1074
            );
1075
            if (empty($docInfo)) {
1076
                return false;
1077
            }
1078
            $path = $docInfo['path'];
1079
        }
1080
1081
        $documentId = intval($documentId);
1082
1083
        if (empty($path) || empty($docInfo) || empty($documentId)) {
1084
            return false;
1085
        }
1086
1087
        $itemInfo = api_get_item_property_info(
1088
            $_course['real_id'],
1089
            TOOL_DOCUMENT,
1090
            $documentId,
1091
            $sessionId,
1092
            $groupId
1093
        );
1094
1095
        if (empty($itemInfo)) {
1096
            return false;
1097
        }
1098
1099
        // File was already deleted.
1100
        if ($itemInfo['lastedit_type'] == 'DocumentDeleted' ||
1101
            $itemInfo['lastedit_type'] == 'delete' ||
1102
            $itemInfo['visibility'] == 2
1103
        ) {
1104
            return false;
1105
        }
1106
1107
        // Filtering by group.
1108
        if ($itemInfo['to_group_id'] != $groupId) {
1109
            return false;
1110
        }
1111
1112
        $document_exists_in_disk = file_exists($base_work_dir.$path);
1113
        $new_path = $path.'_DELETED_'.$documentId;
1114
1115
        $file_deleted_from_db = false;
1116
        $file_deleted_from_disk = false;
1117
        $file_renamed_from_disk = false;
1118
1119
        if ($documentId) {
1120
            // Deleting doc from the DB.
1121
            self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1122
            // Checking
1123
            // $file_exists_in_db = self::get_document_data_by_id($documentId, $_course['code']);
1124
            $file_deleted_from_db = true;
1125
        }
1126
1127
        // Looking for children.
1128
        if ($docInfo['filetype'] == 'folder') {
1129
            $cleanPath = Database::escape_string($path);
1130
1131
            // Deleted files inside this folder.
1132
            $sql = "SELECT id FROM $TABLE_DOCUMENT
1133
                    WHERE
1134
                        c_id = $course_id AND
1135
                        session_id = $sessionId AND
1136
                        path LIKE BINARY '".$cleanPath."/%'";
1137
1138
            // Get all id's of documents that are deleted.
1139
            $result = Database::query($sql);
1140
1141
            if ($result && Database::num_rows($result) != 0) {
1142
                // Recursive delete.
1143
                while ($row = Database::fetch_array($result)) {
1144
                    self::delete_document(
1145
                        $_course,
1146
                        null,
1147
                        $base_work_dir,
1148
                        $sessionId,
1149
                        $row['id'],
1150
                        $groupId
1151
                    );
1152
                }
1153
            }
1154
        }
1155
1156
        if ($document_exists_in_disk) {
1157
            if (api_get_setting('permanently_remove_deleted_files') === 'true') {
1158
                // Delete documents, do it like this so metadata gets deleted too
1159
                my_delete($base_work_dir.$path);
1160
                // Hard delete.
1161
                self::deleteDocumentFromDb($documentId, $_course, $sessionId, true);
1162
                $file_deleted_from_disk = true;
1163
            } else {
1164
                // Set visibility to 2 and rename file/folder to xxx_DELETED_#id (soft delete)
1165
                if (is_file($base_work_dir.$path) || is_dir($base_work_dir.$path)) {
1166
                    if (rename($base_work_dir.$path, $base_work_dir.$new_path)) {
1167
                        $new_path = Database::escape_string($new_path);
1168
1169
                        $sql = "UPDATE $TABLE_DOCUMENT
1170
                                SET path = '".$new_path."'
1171
                                WHERE
1172
                                    c_id = $course_id AND
1173
                                    session_id = $sessionId AND
1174
                                    id = ".$documentId;
1175
                        Database::query($sql);
1176
1177
                        // Soft delete.
1178
                        self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1179
1180
                        // Change path of sub folders and documents in database.
1181
                        $old_item_path = $docInfo['path'];
1182
                        $new_item_path = $new_path.substr($old_item_path, strlen($path));
1183
                        $new_item_path = Database::escape_string($new_item_path);
1184
1185
                        $sql = "UPDATE $TABLE_DOCUMENT
1186
                                SET path = '".$new_item_path."'
1187
                                WHERE
1188
                                    c_id = $course_id AND
1189
                                    session_id = $sessionId AND
1190
                                    id = ".$documentId;
1191
                        Database::query($sql);
1192
1193
                        $file_renamed_from_disk = true;
1194
                    } else {
1195
                        // Couldn't rename - file permissions problem?
1196
                        error_log(
1197
                            __FILE__.' '.__LINE__.': Error renaming '.$base_work_dir.$path.' to '.$base_work_dir.$new_path.'. This is probably due to file permissions',
1198
                            0
1199
                        );
1200
                    }
1201
                }
1202
            }
1203
        }
1204
        // Checking inconsistency
1205
        //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').')');
1206
        if ($file_deleted_from_db && $file_deleted_from_disk ||
1207
            $file_deleted_from_db && $file_renamed_from_disk
1208
        ) {
1209
            return true;
1210
        } else {
1211
            //Something went wrong
1212
            //The file or directory isn't there anymore (on the filesystem)
1213
            // This means it has been removed externally. To prevent a
1214
            // blocking error from happening, we drop the related items from the
1215
            // item_property and the document table.
1216
            error_log(
1217
                __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',
1218
                0
1219
            );
1220
1221
            return false;
1222
        }
1223
    }
1224
1225
    /**
1226
     * Removes documents from search engine database.
1227
     *
1228
     * @param string $course_id   Course code
1229
     * @param int    $document_id Document id to delete
1230
     */
1231
    public static function delete_document_from_search_engine($course_id, $document_id)
1232
    {
1233
        // remove from search engine if enabled
1234
        if (api_get_setting('search_enabled') === 'true') {
1235
            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
1236
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1237
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1238
            $res = Database::query($sql);
1239
            if (Database::num_rows($res) > 0) {
1240
                $row2 = Database::fetch_array($res);
1241
                $di = new ChamiloIndexer();
1242
                $di->remove_document($row2['search_did']);
1243
            }
1244
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1245
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1246
            Database::query($sql);
1247
1248
            // remove terms from db
1249
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1250
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $document_id);
1251
        }
1252
    }
1253
1254
    /**
1255
     * Gets the id of a document with a given path.
1256
     *
1257
     * @param array  $courseInfo
1258
     * @param string $path
1259
     * @param int    $sessionId
1260
     *
1261
     * @return int id of document / false if no doc found
1262
     */
1263
    public static function get_document_id($courseInfo, $path, $sessionId = null)
1264
    {
1265
        $table = Database::get_course_table(TABLE_DOCUMENT);
1266
        $courseId = $courseInfo['real_id'];
1267
1268
        if (!isset($sessionId)) {
1269
            $sessionId = api_get_session_id();
1270
        } else {
1271
            $sessionId = intval($sessionId);
1272
        }
1273
1274
        $path = Database::escape_string($path);
1275
        if (!empty($courseId) && !empty($path)) {
1276
            $sql = "SELECT id FROM $table
1277
                    WHERE
1278
                        c_id = $courseId AND
1279
                        path LIKE BINARY '$path' AND
1280
                        session_id = $sessionId
1281
                    LIMIT 1";
1282
1283
            $result = Database::query($sql);
1284
            if (Database::num_rows($result)) {
1285
                $row = Database::fetch_array($result);
1286
1287
                return intval($row['id']);
1288
            }
1289
        }
1290
1291
        return false;
1292
    }
1293
1294
    /**
1295
     * Gets the document data with a given id.
1296
     *
1297
     * @param int    $id           Document Id (id field in c_document table)
1298
     * @param string $course_code  Course code
1299
     * @param bool   $load_parents load folder parents
1300
     * @param int    $session_id   The session ID,
1301
     *                             0 if requires context *out of* session, and null to use global context
1302
     *
1303
     * @return array document content
1304
     */
1305
    public static function get_document_data_by_id(
1306
        $id,
1307
        $course_code,
1308
        $load_parents = false,
1309
        $session_id = null
1310
    ) {
1311
        $course_info = api_get_course_info($course_code);
1312
        $course_id = $course_info['real_id'];
1313
1314
        if (empty($course_info)) {
1315
            return false;
1316
        }
1317
1318
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
1319
        $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
1320
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1321
        $id = intval($id);
1322
        $sessionCondition = api_get_session_condition($session_id, true, true);
1323
1324
        $sql = "SELECT * FROM $TABLE_DOCUMENT
1325
                WHERE c_id = $course_id $sessionCondition AND id = $id";
1326
1327
        $result = Database::query($sql);
1328
        if ($result && Database::num_rows($result) == 1) {
1329
            $row = Database::fetch_array($result, 'ASSOC');
1330
            //@todo need to clarify the name of the URLs not nice right now
1331
            $url_path = urlencode($row['path']);
1332
            $path = str_replace('%2F', '/', $url_path);
1333
            $pathinfo = pathinfo($row['path']);
1334
1335
            $row['url'] = api_get_path(WEB_CODE_PATH).'document/showinframes.php?cidReq='.$course_code.'&id='.$id;
1336
            $row['document_url'] = api_get_path(WEB_CODE_PATH).'document/document.php?cidReq='.$course_code.'&id='.$id;
1337
            $row['absolute_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
1338
            $row['absolute_path_from_document'] = '/document'.$row['path'];
1339
            $row['absolute_parent_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$pathinfo['dirname'].'/';
1340
            $row['direct_url'] = $www.$path;
1341
            $row['basename'] = basename($row['path']);
1342
1343
            if (dirname($row['path']) == '.') {
1344
                $row['parent_id'] = '0';
1345
            } else {
1346
                $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), $session_id);
1347
            }
1348
            $parents = [];
1349
1350
            //Use to generate parents (needed for the breadcrumb)
1351
            //@todo sorry but this for is here because there's not a parent_id in the document table so we parsed the path!!
1352
            if ($load_parents) {
1353
                $dir_array = explode('/', $row['path']);
1354
                $dir_array = array_filter($dir_array);
1355
                $array_len = count($dir_array) + 1;
1356
                $real_dir = '';
1357
1358
                for ($i = 1; $i < $array_len; $i++) {
1359
                    $real_dir .= '/'.(isset($dir_array[$i]) ? $dir_array[$i] : '');
1360
                    $parent_id = self::get_document_id($course_info, $real_dir);
1361
                    if ($session_id != 0 && empty($parent_id)) {
1362
                        $parent_id = self::get_document_id($course_info, $real_dir, 0);
1363
                    }
1364
                    if (!empty($parent_id)) {
1365
                        $sub_document_data = self::get_document_data_by_id(
1366
                            $parent_id,
1367
                            $course_code,
1368
                            false,
1369
                            $session_id
1370
                        );
1371
                        if ($session_id != 0 and !$sub_document_data) {
1372
                            $sub_document_data = self::get_document_data_by_id(
1373
                                $parent_id,
1374
                                $course_code,
1375
                                false,
1376
                                0
1377
                            );
1378
                        }
1379
                        //@todo add visibility here
1380
                        $parents[] = $sub_document_data;
1381
                    }
1382
                }
1383
            }
1384
            $row['parents'] = $parents;
1385
1386
            return $row;
1387
        }
1388
1389
        return false;
1390
    }
1391
1392
    /**
1393
     * Allow to set a specific document as a new template for CKeditor
1394
     * for a particular user in a particular course.
1395
     *
1396
     * @param string $title
1397
     * @param string $description
1398
     * @param int    $document_id_for_template the document id
1399
     * @param string $course_code
1400
     * @param int    $user_id
1401
     * @param string $image
1402
     *
1403
     * @return bool
1404
     */
1405
    public static function set_document_as_template(
1406
        $title,
1407
        $description,
1408
        $document_id_for_template,
1409
        $course_code,
1410
        $user_id,
1411
        $image
1412
    ) {
1413
        // Database table definition
1414
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1415
        $params = [
1416
            'title' => $title,
1417
            'description' => $description,
1418
            'course_code' => $course_code,
1419
            'user_id' => $user_id,
1420
            'ref_doc' => $document_id_for_template,
1421
            'image' => $image,
1422
        ];
1423
        Database::insert($table_template, $params);
1424
1425
        return true;
1426
    }
1427
1428
    /**
1429
     * Unset a document as template.
1430
     *
1431
     * @param int    $document_id
1432
     * @param string $course_code
1433
     * @param int    $user_id
1434
     */
1435
    public static function unset_document_as_template(
1436
        $document_id,
1437
        $course_code,
1438
        $user_id
1439
    ) {
1440
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1441
        $course_code = Database::escape_string($course_code);
1442
        $user_id = intval($user_id);
1443
        $document_id = intval($document_id);
1444
        $sql = 'SELECT id FROM '.$table_template.'
1445
                WHERE
1446
                    course_code="'.$course_code.'" AND
1447
                    user_id="'.$user_id.'" AND
1448
                    ref_doc="'.$document_id.'"';
1449
        $result = Database::query($sql);
1450
        $template_id = Database::result($result, 0, 0);
1451
1452
        my_delete(api_get_path(SYS_CODE_PATH).'upload/template_thumbnails/'.$template_id.'.jpg');
1453
1454
        $sql = 'DELETE FROM '.$table_template.'
1455
                WHERE
1456
                    course_code="'.$course_code.'" AND
1457
                    user_id="'.$user_id.'" AND
1458
                    ref_doc="'.$document_id.'"';
1459
1460
        Database::query($sql);
1461
    }
1462
1463
    /**
1464
     * Return true if the documentpath have visibility=1 as
1465
     * item_property (you should use the is_visible_by_id).
1466
     *
1467
     * @param string $doc_path the relative complete path of the document
1468
     * @param array  $course   the _course array info of the document's course
1469
     * @param int
1470
     * @param string
1471
     *
1472
     * @return bool
1473
     */
1474
    public static function is_visible(
1475
        $doc_path,
1476
        $course,
1477
        $session_id = 0,
1478
        $file_type = 'file'
1479
    ) {
1480
        $docTable = Database::get_course_table(TABLE_DOCUMENT);
1481
        $propTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
1482
1483
        $course_id = $course['real_id'];
1484
        // note the extra / at the end of doc_path to match every path in
1485
        // the document table that is part of the document path
1486
1487
        $session_id = intval($session_id);
1488
        $condition = "AND d.session_id IN  ('$session_id', '0') ";
1489
        // The " d.filetype='file' " let the user see a file even if the folder is hidden see #2198
1490
1491
        /*
1492
          When using hotpotatoes files, a new html files are generated
1493
          in the hotpotatoes folder to display the test.
1494
          The genuine html file is copied to math4.htm(user_id).t.html
1495
          Images files are not copied, and keep same name.
1496
          To check the html file visibility, we don't have to check file math4.htm(user_id).t.html but file math4.htm
1497
          In this case, we have to remove (user_id).t.html to check the visibility of the file
1498
          For images, we just check the path of the image file.
1499
1500
          Exemple of hotpotatoes folder :
1501
          A.jpg
1502
          maths4-consigne.jpg
1503
          maths4.htm
1504
          maths4.htm1.t.html
1505
          maths4.htm52.t.html
1506
          maths4.htm654.t.html
1507
          omega.jpg
1508
          theta.jpg
1509
         */
1510
1511
        if (strpos($doc_path, 'HotPotatoes_files') && preg_match("/\.t\.html$/", $doc_path)) {
1512
            $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
1513
        }
1514
1515
        if (!in_array($file_type, ['file', 'folder'])) {
1516
            $file_type = 'file';
1517
        }
1518
        $doc_path = Database::escape_string($doc_path).'/';
1519
1520
        $sql = "SELECT visibility
1521
                FROM $docTable d
1522
                INNER JOIN $propTable ip
1523
                ON (d.id = ip.ref AND d.c_id = ip.c_id)
1524
        		WHERE
1525
        		    d.c_id  = $course_id AND 
1526
        		    ip.c_id = $course_id AND
1527
        		    ip.tool = '".TOOL_DOCUMENT."' $condition AND
1528
        			filetype = '$file_type' AND
1529
        			locate(concat(path,'/'), '$doc_path')=1
1530
                ";
1531
1532
        $result = Database::query($sql);
1533
        $is_visible = false;
1534
        if (Database::num_rows($result) > 0) {
1535
            $row = Database::fetch_array($result, 'ASSOC');
1536
            if ($row['visibility'] == 1) {
1537
                $is_visible = api_is_allowed_in_course() || api_is_platform_admin();
1538
            }
1539
        }
1540
1541
        /* improved protection of documents viewable directly through the url:
1542
            incorporates the same protections of the course at the url of
1543
            documents:
1544
            access allowed for the whole world Open, access allowed for
1545
            users registered on the platform Private access, document accessible
1546
            only to course members (see the Users list), Completely closed;
1547
            the document is only accessible to the course admin and
1548
            teaching assistants.*/
1549
        //return $_SESSION ['is_allowed_in_course'] || api_is_platform_admin();
1550
        return $is_visible;
1551
    }
1552
1553
    /**
1554
     * Return true if user can see a file.
1555
     *
1556
     * @param   int     document id
1557
     * @param   array   course info
1558
     * @param   int
1559
     * @param   int
1560
     * @param bool
1561
     *
1562
     * @return bool
1563
     */
1564
    public static function is_visible_by_id(
1565
        $doc_id,
1566
        $course_info,
1567
        $session_id,
1568
        $user_id,
1569
        $admins_can_see_everything = true,
1570
        $userIsSubscribed = null
1571
    ) {
1572
        $user_in_course = false;
1573
1574
        //1. Checking the course array
1575
        if (empty($course_info)) {
1576
            $course_info = api_get_course_info();
1577
            if (empty($course_info)) {
1578
                return false;
1579
            }
1580
        }
1581
1582
        $doc_id = intval($doc_id);
1583
        $session_id = intval($session_id);
1584
1585
        //2. Course and Session visibility are handle in local.inc.php/global.inc.php
1586
        //3. Checking if user exist in course/session
1587
        if ($session_id == 0) {
1588
            if (is_null($userIsSubscribed)) {
1589
                $userIsSubscribed = CourseManager::is_user_subscribed_in_course(
1590
                    $user_id,
1591
                    $course_info['code']
1592
                );
1593
            }
1594
1595
            if ($userIsSubscribed === true || api_is_platform_admin()) {
1596
                $user_in_course = true;
1597
            }
1598
1599
            // Check if course is open then we can consider that the student is registered to the course
1600
            if (isset($course_info) &&
1601
                in_array(
1602
                    $course_info['visibility'],
1603
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
1604
                )
1605
            ) {
1606
                $user_in_course = true;
1607
            }
1608
        } else {
1609
            $user_status = SessionManager::get_user_status_in_course_session(
1610
                $user_id,
1611
                $course_info['real_id'],
1612
                $session_id
1613
            );
1614
1615
            if (in_array($user_status, ['0', '2', '6'])) {
1616
                //is true if is an student, course session teacher or coach
1617
                $user_in_course = true;
1618
            }
1619
1620
            if (api_is_platform_admin()) {
1621
                $user_in_course = true;
1622
            }
1623
        }
1624
1625
        // 4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
1626
        if ($user_in_course) {
1627
            // 4.1 Checking document visibility for a Course
1628
            if ($session_id == 0) {
1629
                $item_info = api_get_item_property_info(
1630
                    $course_info['real_id'],
1631
                    'document',
1632
                    $doc_id,
1633
                    0
1634
                );
1635
1636
                if (isset($item_info['visibility'])) {
1637
                    // True for admins if document exists
1638
                    if ($admins_can_see_everything && api_is_platform_admin()) {
1639
                        return true;
1640
                    }
1641
                    if ($item_info['visibility'] == 1) {
1642
                        return true;
1643
                    }
1644
                }
1645
            } else {
1646
                // 4.2 Checking document visibility for a Course in a Session
1647
                $item_info = api_get_item_property_info(
1648
                    $course_info['real_id'],
1649
                    'document',
1650
                    $doc_id,
1651
                    0
1652
                );
1653
1654
                $item_info_in_session = api_get_item_property_info(
1655
                    $course_info['real_id'],
1656
                    'document',
1657
                    $doc_id,
1658
                    $session_id
1659
                );
1660
1661
                // True for admins if document exists
1662
                if (isset($item_info['visibility'])) {
1663
                    if ($admins_can_see_everything && api_is_platform_admin()) {
1664
                        return true;
1665
                    }
1666
                }
1667
1668
                if (isset($item_info_in_session['visibility'])) {
1669
                    if ($item_info_in_session['visibility'] == 1) {
1670
                        return true;
1671
                    }
1672
                } else {
1673
                    if ($item_info['visibility'] == 1) {
1674
                        return true;
1675
                    }
1676
                }
1677
            }
1678
        } elseif ($admins_can_see_everything && api_is_platform_admin()) {
1679
            return true;
1680
        }
1681
1682
        return false;
1683
    }
1684
1685
    /**
1686
     * Allow attach a certificate to a course.
1687
     *
1688
     * @todo move to certificate.lib.php
1689
     *
1690
     * @param string $course_id
1691
     * @param int    $document_id
1692
     * @param int    $session_id
1693
     */
1694
    public static function attach_gradebook_certificate($course_id, $document_id, $session_id = 0)
1695
    {
1696
        $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1697
        $session_id = intval($session_id);
1698
        if (empty($session_id)) {
1699
            $session_id = api_get_session_id();
1700
        }
1701
1702
        if (empty($session_id)) {
1703
            $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
1704
        } elseif ($session_id > 0) {
1705
            $sql_session = 'AND session_id='.intval($session_id);
1706
        } else {
1707
            $sql_session = '';
1708
        }
1709
        $sql = 'UPDATE '.$tbl_category.' SET document_id="'.intval($document_id).'"
1710
                WHERE course_code="'.Database::escape_string($course_id).'" '.$sql_session;
1711
        Database::query($sql);
1712
    }
1713
1714
    /**
1715
     * get the document id of default certificate.
1716
     *
1717
     * @todo move to certificate.lib.php
1718
     *
1719
     * @param string $course_id
1720
     * @param int    $session_id
1721
     *
1722
     * @return int The default certificate id
1723
     */
1724
    public static function get_default_certificate_id($course_id, $session_id = 0)
1725
    {
1726
        $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1727
        $session_id = intval($session_id);
1728
        if (empty($session_id)) {
1729
            $session_id = api_get_session_id();
1730
        }
1731
1732
        if (empty($session_id)) {
1733
            $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
1734
        } elseif ($session_id > 0) {
1735
            $sql_session = 'AND session_id='.intval($session_id);
1736
        } else {
1737
            $sql_session = '';
1738
        }
1739
        $sql = 'SELECT document_id FROM '.$tbl_category.'
1740
                WHERE course_code="'.Database::escape_string($course_id).'" '.$sql_session;
1741
1742
        $rs = Database::query($sql);
1743
        $num = Database::num_rows($rs);
1744
        if ($num == 0) {
1745
            return null;
1746
        }
1747
        $row = Database::fetch_array($rs);
1748
1749
        return $row['document_id'];
1750
    }
1751
1752
    /**
1753
     * Allow replace user info in file html.
1754
     *
1755
     * @param int    $user_id
1756
     * @param string $course_code
1757
     * @param int    $sessionId
1758
     * @param bool   $is_preview
1759
     *
1760
     * @return array
1761
     */
1762
    public static function replace_user_info_into_html(
1763
        $user_id,
1764
        $course_code,
1765
        $sessionId,
1766
        $is_preview = false
1767
    ) {
1768
        $user_id = intval($user_id);
1769
        $course_info = api_get_course_info($course_code);
1770
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
1771
        $course_id = $course_info['real_id'];
1772
1773
        $document_id = self::get_default_certificate_id(
1774
            $course_code,
1775
            $sessionId
1776
        );
1777
1778
        $my_content_html = null;
1779
        if ($document_id) {
1780
            $sql = "SELECT path FROM $tbl_document
1781
                    WHERE c_id = $course_id AND id = $document_id";
1782
            $rs = Database::query($sql);
1783
            $new_content = '';
1784
            $all_user_info = [];
1785
            if (Database::num_rows($rs)) {
1786
                $row = Database::fetch_array($rs);
1787
                $filepath = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
1788
                if (is_file($filepath)) {
1789
                    $my_content_html = file_get_contents($filepath);
1790
                }
1791
                $all_user_info = self::get_all_info_to_certificate(
1792
                    $user_id,
1793
                    $course_code,
1794
                    $is_preview
1795
                );
1796
1797
                $info_to_be_replaced_in_content_html = $all_user_info[0];
1798
                $info_to_replace_in_content_html = $all_user_info[1];
1799
                $new_content = str_replace(
1800
                    $info_to_be_replaced_in_content_html,
1801
                    $info_to_replace_in_content_html,
1802
                    $my_content_html
1803
                );
1804
            }
1805
1806
            return [
1807
                'content' => $new_content,
1808
                'variables' => $all_user_info,
1809
            ];
1810
        }
1811
1812
        return [];
1813
    }
1814
1815
    /**
1816
     * Return all content to replace and all content to be replace.
1817
     *
1818
     * @param int  $user_id
1819
     * @param int  $course_id
1820
     * @param bool $is_preview
1821
     *
1822
     * @return array
1823
     */
1824
    public static function get_all_info_to_certificate($user_id, $course_id, $is_preview = false)
1825
    {
1826
        $info_list = [];
1827
        $user_id = intval($user_id);
1828
        $course_info = api_get_course_info($course_id);
1829
1830
        // Portal info
1831
        $organization_name = api_get_setting('Institution');
1832
        $portal_name = api_get_setting('siteName');
1833
1834
        // Extra user data information
1835
        $extra_user_info_data = UserManager::get_extra_user_data(
1836
            $user_id,
1837
            false,
1838
            false,
1839
            false,
1840
            true
1841
        );
1842
1843
        // get extra fields
1844
        $extraField = new ExtraField('user');
1845
        $extraFields = $extraField->get_all(['filter = ? AND visible_to_self = ?' => [1, 1]]);
1846
1847
        // Student information
1848
        $user_info = api_get_user_info($user_id);
1849
        $first_name = $user_info['firstname'];
1850
        $last_name = $user_info['lastname'];
1851
        $official_code = $user_info['official_code'];
1852
1853
        // Teacher information
1854
        $info_teacher_id = UserManager::get_user_id_of_course_admin_or_session_admin($course_info);
1855
        $teacher_info = api_get_user_info($info_teacher_id);
1856
        $teacher_first_name = $teacher_info['firstname'];
1857
        $teacher_last_name = $teacher_info['lastname'];
1858
1859
        // info gradebook certificate
1860
        $info_grade_certificate = UserManager::get_info_gradebook_certificate($course_id, $user_id);
1861
        $date_certificate = $info_grade_certificate['created_at'];
1862
        $date_long_certificate = '';
1863
1864
        $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
1865
        if (!empty($date_certificate)) {
1866
            $date_long_certificate = api_convert_and_format_date($date_certificate);
1867
            $date_no_time = api_convert_and_format_date($date_certificate, DATE_FORMAT_LONG_NO_DAY);
1868
        }
1869
1870
        if ($is_preview) {
1871
            $date_long_certificate = api_convert_and_format_date(api_get_utc_datetime());
1872
            $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
1873
        }
1874
1875
        $url = api_get_path(WEB_PATH).'certificates/index.php?id='.$info_grade_certificate['id'];
1876
        $externalStyleFile = api_get_path(SYS_CSS_PATH).'themes/'.api_get_visual_theme().'/certificate.css';
1877
        $externalStyle = '';
1878
        if (is_file($externalStyleFile)) {
1879
            $externalStyle = file_get_contents($externalStyleFile);
1880
        }
1881
1882
        // Replace content
1883
        $info_to_replace_in_content_html = [
1884
            $first_name,
1885
            $last_name,
1886
            $organization_name,
1887
            $portal_name,
1888
            $teacher_first_name,
1889
            $teacher_last_name,
1890
            $official_code,
1891
            $date_long_certificate,
1892
            $date_no_time,
1893
            $course_id,
1894
            $course_info['name'],
1895
            $info_grade_certificate['grade'],
1896
            $url,
1897
            '<a href="'.$url.'" target="_blank">'.get_lang('CertificateOnlineLink').'</a>',
1898
            '((certificate_barcode))',
1899
            $externalStyle,
1900
        ];
1901
1902
        $tags = [
1903
            '((user_firstname))',
1904
            '((user_lastname))',
1905
            '((gradebook_institution))',
1906
            '((gradebook_sitename))',
1907
            '((teacher_firstname))',
1908
            '((teacher_lastname))',
1909
            '((official_code))',
1910
            '((date_certificate))',
1911
            '((date_certificate_no_time))',
1912
            '((course_code))',
1913
            '((course_title))',
1914
            '((gradebook_grade))',
1915
            '((certificate_link))',
1916
            '((certificate_link_html))',
1917
            '((certificate_barcode))',
1918
            '((external_style))',
1919
        ];
1920
1921
        if (!empty($extraFields)) {
1922
            foreach ($extraFields as $extraField) {
1923
                $valueExtra = isset($extra_user_info_data[$extraField['variable']]) ? $extra_user_info_data[$extraField['variable']] : '';
1924
                $tags[] = '(('.strtolower($extraField['variable']).'))';
1925
                $info_to_replace_in_content_html[] = $valueExtra;
1926
            }
1927
        }
1928
1929
        $info_list[] = $tags;
1930
        $info_list[] = $info_to_replace_in_content_html;
1931
1932
        return $info_list;
1933
    }
1934
1935
    /**
1936
     * Remove default certificate.
1937
     *
1938
     * @param string $course_id              The course code
1939
     * @param int    $default_certificate_id The document id of the default certificate
1940
     */
1941
    public static function remove_attach_certificate($course_id, $default_certificate_id)
1942
    {
1943
        if (empty($default_certificate_id)) {
1944
            return false;
1945
        }
1946
1947
        $default_certificate = self::get_default_certificate_id($course_id);
1948
        if ((int) $default_certificate == (int) $default_certificate_id) {
1949
            $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1950
            $session_id = api_get_session_id();
1951
            if ($session_id == 0 || is_null($session_id)) {
1952
                $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
1953
            } elseif ($session_id > 0) {
1954
                $sql_session = 'AND session_id='.intval($session_id);
1955
            } else {
1956
                $sql_session = '';
1957
            }
1958
1959
            $sql = 'UPDATE '.$tbl_category.' SET document_id = null
1960
                    WHERE
1961
                        course_code = "'.Database::escape_string($course_id).'" AND
1962
                        document_id="'.$default_certificate_id.'" '.$sql_session;
1963
            Database::query($sql);
1964
        }
1965
    }
1966
1967
    /**
1968
     * Create directory certificate.
1969
     *
1970
     * @param array $courseInfo
1971
     */
1972
    public static function create_directory_certificate_in_course($courseInfo)
1973
    {
1974
        if (!empty($courseInfo)) {
1975
            $to_group_id = 0;
1976
            $to_user_id = null;
1977
            $course_dir = $courseInfo['path']."/document/";
1978
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
1979
            $base_work_dir = $sys_course_path.$course_dir;
1980
            $dir_name = '/certificates';
1981
            $post_dir_name = get_lang('CertificatesFiles');
1982
            $visibility_command = 'invisible';
1983
1984
            $id = self::get_document_id_of_directory_certificate();
1985
1986
            if (empty($id)) {
1987
                create_unexisting_directory(
1988
                    $courseInfo,
1989
                    api_get_user_id(),
1990
                    api_get_session_id(),
1991
                    $to_group_id,
1992
                    $to_user_id,
1993
                    $base_work_dir,
1994
                    $dir_name,
1995
                    $post_dir_name,
1996
                    null,
1997
                    false,
1998
                    false
1999
                );
2000
2001
                $id = self::get_document_id_of_directory_certificate();
2002
2003
                if (empty($id)) {
2004
                    $id = add_document(
2005
                        $courseInfo,
2006
                        $dir_name,
2007
                        'folder',
2008
                        0,
2009
                        $post_dir_name,
2010
                        null,
2011
                        0,
2012
                        true,
2013
                        $to_group_id,
2014
                        0,
2015
                        0,
2016
                        false
2017
                    );
2018
                }
2019
2020
                if (!empty($id)) {
2021
                    api_item_property_update(
2022
                        $courseInfo,
2023
                        TOOL_DOCUMENT,
2024
                        $id,
2025
                        $visibility_command,
2026
                        api_get_user_id()
2027
                    );
2028
                }
2029
            }
2030
        }
2031
    }
2032
2033
    /**
2034
     * Get the document id of the directory certificate.
2035
     *
2036
     * @return int The document id of the directory certificate
2037
     *
2038
     * @todo move to certificate.lib.php
2039
     */
2040
    public static function get_document_id_of_directory_certificate()
2041
    {
2042
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
2043
        $course_id = api_get_course_int_id();
2044
        $sql = "SELECT id FROM $tbl_document 
2045
                WHERE c_id = $course_id AND path='/certificates' ";
2046
        $rs = Database::query($sql);
2047
        $row = Database::fetch_array($rs);
2048
2049
        return $row['id'];
2050
    }
2051
2052
    /**
2053
     * Check if a directory given is for certificate.
2054
     *
2055
     * @todo move to certificate.lib.php
2056
     *
2057
     * @param string $dir path of directory
2058
     *
2059
     * @return bool true if is a certificate or false otherwise
2060
     */
2061
    public static function is_certificate_mode($dir)
2062
    {
2063
        // I'm in the certification module?
2064
        $is_certificate_mode = false;
2065
        $is_certificate_array = explode('/', $dir);
2066
        array_shift($is_certificate_array);
2067
        if (isset($is_certificate_array[0]) && $is_certificate_array[0] == 'certificates') {
2068
            $is_certificate_mode = true;
2069
        }
2070
2071
        return $is_certificate_mode || (isset($_GET['certificate']) && $_GET['certificate'] === 'true');
2072
    }
2073
2074
    /**
2075
     * Gets the list of included resources as a list of absolute or relative paths from a html file or string html
2076
     * This allows for a better SCORM export or replace urls inside content html from copy course
2077
     * The list will generally include pictures, flash objects, java applets, or any other
2078
     * stuff included in the source of the current item. The current item is expected
2079
     * to be an HTML file or string html. If it is not, then the function will return and empty list.
2080
     *
2081
     * @param    string  source html (content or path)
2082
     * @param    bool    is file or string html
2083
     * @param    string    type (one of the app tools) - optional (otherwise takes the current item's type)
2084
     * @param    int        level of recursivity we're in
2085
     *
2086
     * @return array List of file paths. An additional field containing 'local' or 'remote' helps determine
2087
     *               if the file should be copied into the zip or just linked
2088
     */
2089
    public static function get_resources_from_source_html(
2090
        $source_html,
2091
        $is_file = false,
2092
        $type = null,
2093
        $recursivity = 1
2094
    ) {
2095
        $max = 5;
2096
        $attributes = [];
2097
        $wanted_attributes = [
2098
            'src',
2099
            'url',
2100
            '@import',
2101
            'href',
2102
            'value',
2103
            'flashvars',
2104
            'poster',
2105
        ];
2106
        $explode_attributes = ['flashvars' => 'file'];
2107
        $abs_path = '';
2108
2109
        if ($recursivity > $max) {
2110
            return [];
2111
        }
2112
2113
        if (!isset($type)) {
2114
            $type = TOOL_DOCUMENT;
2115
        }
2116
2117
        if (!$is_file) {
2118
            $attributes = self::parse_HTML_attributes(
2119
                $source_html,
2120
                $wanted_attributes,
2121
                $explode_attributes
2122
            );
2123
        } else {
2124
            if (is_file($source_html)) {
2125
                $abs_path = $source_html;
2126
                //for now, read the whole file in one go (that's gonna be a problem when the file is too big)
2127
                $info = pathinfo($abs_path);
2128
                $ext = $info['extension'];
2129
                switch (strtolower($ext)) {
2130
                    case 'html':
2131
                    case 'htm':
2132
                    case 'shtml':
2133
                    case 'css':
2134
                        $file_content = file_get_contents($abs_path);
2135
                        // get an array of attributes from the HTML source
2136
                        $attributes = self::parse_HTML_attributes(
2137
                            $file_content,
2138
                            $wanted_attributes,
2139
                            $explode_attributes
2140
                        );
2141
                        break;
2142
                    default:
2143
                        break;
2144
                }
2145
            } else {
2146
                return false;
2147
            }
2148
        }
2149
2150
        $files_list = [];
2151
        switch ($type) {
2152
            case TOOL_DOCUMENT:
2153
            case TOOL_QUIZ:
2154
            case 'sco':
2155
                foreach ($wanted_attributes as $attr) {
2156
                    if (isset($attributes[$attr])) {
2157
                        //find which kind of path these are (local or remote)
2158
                        $sources = $attributes[$attr];
2159
                        foreach ($sources as $source) {
2160
                            //skip what is obviously not a resource
2161
                            if (strpos($source, '+this.')) {
2162
                                continue; //javascript code - will still work unaltered
2163
                            }
2164
                            if (strpos($source, '.') === false) {
2165
                                continue; //no dot, should not be an external file anyway
2166
                            }
2167
                            if (strpos($source, 'mailto:')) {
2168
                                continue; //mailto link
2169
                            }
2170
                            if (strpos($source, ';') && !strpos($source, '&amp;')) {
2171
                                continue; //avoid code - that should help
2172
                            }
2173
2174
                            if ($attr == 'value') {
2175
                                if (strpos($source, 'mp3file')) {
2176
                                    $files_list[] = [
2177
                                        substr($source, 0, strpos($source, '.swf') + 4),
2178
                                        'local',
2179
                                        'abs',
2180
                                    ];
2181
                                    $mp3file = substr($source, strpos($source, 'mp3file=') + 8);
2182
                                    if (substr($mp3file, 0, 1) == '/') {
2183
                                        $files_list[] = [$mp3file, 'local', 'abs'];
2184
                                    } else {
2185
                                        $files_list[] = [$mp3file, 'local', 'rel'];
2186
                                    }
2187
                                } elseif (strpos($source, 'flv=') === 0) {
2188
                                    $source = substr($source, 4);
2189
                                    if (strpos($source, '&') > 0) {
2190
                                        $source = substr($source, 0, strpos($source, '&'));
2191
                                    }
2192
                                    if (strpos($source, '://') > 0) {
2193
                                        if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2194
                                            //we found the current portal url
2195
                                            $files_list[] = [$source, 'local', 'url'];
2196
                                        } else {
2197
                                            //we didn't find any trace of current portal
2198
                                            $files_list[] = [$source, 'remote', 'url'];
2199
                                        }
2200
                                    } else {
2201
                                        $files_list[] = [$source, 'local', 'abs'];
2202
                                    }
2203
                                    /* skipping anything else to avoid two entries
2204
                                    (while the others can have sub-files in their url, flv's can't)*/
2205
                                    continue;
2206
                                }
2207
                            }
2208
                            if (strpos($source, '://') > 0) {
2209
                                //cut at '?' in a URL with params
2210
                                if (strpos($source, '?') > 0) {
2211
                                    $second_part = substr($source, strpos($source, '?'));
2212
                                    if (strpos($second_part, '://') > 0) {
2213
                                        //if the second part of the url contains a url too, treat the second one before cutting
2214
                                        $pos1 = strpos($second_part, '=');
2215
                                        $pos2 = strpos($second_part, '&');
2216
                                        $second_part = substr($second_part, $pos1 + 1, $pos2 - ($pos1 + 1));
2217
                                        if (strpos($second_part, api_get_path(WEB_PATH)) !== false) {
2218
                                            //we found the current portal url
2219
                                            $files_list[] = [$second_part, 'local', 'url'];
2220
                                            $in_files_list[] = self::get_resources_from_source_html(
2221
                                                $second_part,
2222
                                                true,
2223
                                                TOOL_DOCUMENT,
2224
                                                $recursivity + 1
2225
                                            );
2226
                                            if (count($in_files_list) > 0) {
2227
                                                $files_list = array_merge($files_list, $in_files_list);
2228
                                            }
2229
                                        } else {
2230
                                            //we didn't find any trace of current portal
2231
                                            $files_list[] = [$second_part, 'remote', 'url'];
2232
                                        }
2233
                                    } elseif (strpos($second_part, '=') > 0) {
2234
                                        if (substr($second_part, 0, 1) === '/') {
2235
                                            //link starts with a /, making it absolute (relative to DocumentRoot)
2236
                                            $files_list[] = [$second_part, 'local', 'abs'];
2237
                                            $in_files_list[] = self::get_resources_from_source_html(
2238
                                                $second_part,
2239
                                                true,
2240
                                                TOOL_DOCUMENT,
2241
                                                $recursivity + 1
2242
                                            );
2243
                                            if (count($in_files_list) > 0) {
2244
                                                $files_list = array_merge($files_list, $in_files_list);
2245
                                            }
2246
                                        } elseif (strstr($second_part, '..') === 0) {
2247
                                            //link is relative but going back in the hierarchy
2248
                                            $files_list[] = [$second_part, 'local', 'rel'];
2249
                                            //$dir = api_get_path(SYS_CODE_PATH);//dirname($abs_path);
2250
                                            //$new_abs_path = realpath($dir.'/'.$second_part);
2251
                                            $dir = '';
2252
                                            if (!empty($abs_path)) {
2253
                                                $dir = dirname($abs_path).'/';
2254
                                            }
2255
                                            $new_abs_path = realpath($dir.$second_part);
2256
                                            $in_files_list[] = self::get_resources_from_source_html(
2257
                                                $new_abs_path,
2258
                                                true,
2259
                                                TOOL_DOCUMENT,
2260
                                                $recursivity + 1
2261
                                            );
2262
                                            if (count($in_files_list) > 0) {
2263
                                                $files_list = array_merge($files_list, $in_files_list);
2264
                                            }
2265
                                        } else {
2266
                                            //no starting '/', making it relative to current document's path
2267
                                            if (substr($second_part, 0, 2) == './') {
2268
                                                $second_part = substr($second_part, 2);
2269
                                            }
2270
                                            $files_list[] = [$second_part, 'local', 'rel'];
2271
                                            $dir = '';
2272
                                            if (!empty($abs_path)) {
2273
                                                $dir = dirname($abs_path).'/';
2274
                                            }
2275
                                            $new_abs_path = realpath($dir.$second_part);
2276
                                            $in_files_list[] = self::get_resources_from_source_html(
2277
                                                $new_abs_path,
2278
                                                true,
2279
                                                TOOL_DOCUMENT,
2280
                                                $recursivity + 1
2281
                                            );
2282
                                            if (count($in_files_list) > 0) {
2283
                                                $files_list = array_merge($files_list, $in_files_list);
2284
                                            }
2285
                                        }
2286
                                    }
2287
                                    //leave that second part behind now
2288
                                    $source = substr($source, 0, strpos($source, '?'));
2289
                                    if (strpos($source, '://') > 0) {
2290
                                        if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2291
                                            //we found the current portal url
2292
                                            $files_list[] = [$source, 'local', 'url'];
2293
                                            $in_files_list[] = self::get_resources_from_source_html(
2294
                                                $source,
2295
                                                true,
2296
                                                TOOL_DOCUMENT,
2297
                                                $recursivity + 1
2298
                                            );
2299
                                            if (count($in_files_list) > 0) {
2300
                                                $files_list = array_merge($files_list, $in_files_list);
2301
                                            }
2302
                                        } else {
2303
                                            //we didn't find any trace of current portal
2304
                                            $files_list[] = [$source, 'remote', 'url'];
2305
                                        }
2306
                                    } else {
2307
                                        //no protocol found, make link local
2308
                                        if (substr($source, 0, 1) === '/') {
2309
                                            //link starts with a /, making it absolute (relative to DocumentRoot)
2310
                                            $files_list[] = [$source, 'local', 'abs'];
2311
                                            $in_files_list[] = self::get_resources_from_source_html(
2312
                                                $source,
2313
                                                true,
2314
                                                TOOL_DOCUMENT,
2315
                                                $recursivity + 1
2316
                                            );
2317
                                            if (count($in_files_list) > 0) {
2318
                                                $files_list = array_merge($files_list, $in_files_list);
2319
                                            }
2320
                                        } elseif (strstr($source, '..') === 0) {
2321
                                            //link is relative but going back in the hierarchy
2322
                                            $files_list[] = [$source, 'local', 'rel'];
2323
                                            $dir = '';
2324
                                            if (!empty($abs_path)) {
2325
                                                $dir = dirname($abs_path).'/';
2326
                                            }
2327
                                            $new_abs_path = realpath($dir.$source);
2328
                                            $in_files_list[] = self::get_resources_from_source_html(
2329
                                                $new_abs_path,
2330
                                                true,
2331
                                                TOOL_DOCUMENT,
2332
                                                $recursivity + 1
2333
                                            );
2334
                                            if (count($in_files_list) > 0) {
2335
                                                $files_list = array_merge($files_list, $in_files_list);
2336
                                            }
2337
                                        } else {
2338
                                            //no starting '/', making it relative to current document's path
2339
                                            if (substr($source, 0, 2) == './') {
2340
                                                $source = substr($source, 2);
2341
                                            }
2342
                                            $files_list[] = [$source, 'local', 'rel'];
2343
                                            $dir = '';
2344
                                            if (!empty($abs_path)) {
2345
                                                $dir = dirname($abs_path).'/';
2346
                                            }
2347
                                            $new_abs_path = realpath($dir.$source);
2348
                                            $in_files_list[] = self::get_resources_from_source_html(
2349
                                                $new_abs_path,
2350
                                                true,
2351
                                                TOOL_DOCUMENT,
2352
                                                $recursivity + 1
2353
                                            );
2354
                                            if (count($in_files_list) > 0) {
2355
                                                $files_list = array_merge($files_list, $in_files_list);
2356
                                            }
2357
                                        }
2358
                                    }
2359
                                }
2360
                                //found some protocol there
2361
                                if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2362
                                    //we found the current portal url
2363
                                    $files_list[] = [$source, 'local', 'url'];
2364
                                    $in_files_list[] = self::get_resources_from_source_html(
2365
                                        $source,
2366
                                        true,
2367
                                        TOOL_DOCUMENT,
2368
                                        $recursivity + 1
2369
                                    );
2370
                                    if (count($in_files_list) > 0) {
2371
                                        $files_list = array_merge($files_list, $in_files_list);
2372
                                    }
2373
                                } else {
2374
                                    //we didn't find any trace of current portal
2375
                                    $files_list[] = [$source, 'remote', 'url'];
2376
                                }
2377
                            } else {
2378
                                //no protocol found, make link local
2379
                                if (substr($source, 0, 1) === '/') {
2380
                                    //link starts with a /, making it absolute (relative to DocumentRoot)
2381
                                    $files_list[] = [$source, 'local', 'abs'];
2382
                                    $in_files_list[] = self::get_resources_from_source_html(
2383
                                        $source,
2384
                                        true,
2385
                                        TOOL_DOCUMENT,
2386
                                        $recursivity + 1
2387
                                    );
2388
                                    if (count($in_files_list) > 0) {
2389
                                        $files_list = array_merge($files_list, $in_files_list);
2390
                                    }
2391
                                } elseif (strpos($source, '..') === 0) {
2392
                                    //link is relative but going back in the hierarchy
2393
                                    $files_list[] = [$source, 'local', 'rel'];
2394
                                    $dir = '';
2395
                                    if (!empty($abs_path)) {
2396
                                        $dir = dirname($abs_path).'/';
2397
                                    }
2398
                                    $new_abs_path = realpath($dir.$source);
2399
                                    $in_files_list[] = self::get_resources_from_source_html(
2400
                                        $new_abs_path,
2401
                                        true,
2402
                                        TOOL_DOCUMENT,
2403
                                        $recursivity + 1
2404
                                    );
2405
                                    if (count($in_files_list) > 0) {
2406
                                        $files_list = array_merge($files_list, $in_files_list);
2407
                                    }
2408
                                } else {
2409
                                    //no starting '/', making it relative to current document's path
2410
                                    if (substr($source, 0, 2) == './') {
2411
                                        $source = substr($source, 2);
2412
                                    }
2413
                                    $files_list[] = [$source, 'local', 'rel'];
2414
                                    $dir = '';
2415
                                    if (!empty($abs_path)) {
2416
                                        $dir = dirname($abs_path).'/';
2417
                                    }
2418
                                    $new_abs_path = realpath($dir.$source);
2419
                                    $in_files_list[] = self::get_resources_from_source_html(
2420
                                        $new_abs_path,
2421
                                        true,
2422
                                        TOOL_DOCUMENT,
2423
                                        $recursivity + 1
2424
                                    );
2425
                                    if (count($in_files_list) > 0) {
2426
                                        $files_list = array_merge($files_list, $in_files_list);
2427
                                    }
2428
                                }
2429
                            }
2430
                        }
2431
                    }
2432
                }
2433
                break;
2434
            default: //ignore
2435
                break;
2436
        }
2437
2438
        $checked_files_list = [];
2439
        $checked_array_list = [];
2440
2441
        if (count($files_list) > 0) {
2442
            foreach ($files_list as $idx => $file) {
2443
                if (!empty($file[0])) {
2444
                    if (!in_array($file[0], $checked_files_list)) {
2445
                        $checked_files_list[] = $files_list[$idx][0];
2446
                        $checked_array_list[] = $files_list[$idx];
2447
                    }
2448
                }
2449
            }
2450
        }
2451
2452
        return $checked_array_list;
2453
    }
2454
2455
    /**
2456
     * Parses the HTML attributes given as string.
2457
     *
2458
     * @param string HTML attribute string
2459
     * @param array List of attributes that we want to get back
2460
     * @param array
2461
     *
2462
     * @return array An associative array of attributes
2463
     *
2464
     * @author Based on a function from the HTML_Common2 PEAR module     *
2465
     */
2466
    public static function parse_HTML_attributes($attrString, $wanted = [], $explode_variables = [])
2467
    {
2468
        $attributes = [];
2469
        $regs = [];
2470
        $reduced = false;
2471
        if (count($wanted) > 0) {
2472
            $reduced = true;
2473
        }
2474
        try {
2475
            //Find all occurences of something that looks like a URL
2476
            // The structure of this regexp is:
2477
            // (find protocol) then
2478
            // (optionally find some kind of space 1 or more times) then
2479
            // find (either an equal sign or a bracket) followed by an optional space
2480
            // followed by some text without quotes (between quotes itself or not)
2481
            // then possible closing brackets if we were in the opening bracket case
2482
            // OR something like @import()
2483
            $res = preg_match_all(
2484
                '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]*))'.
2485
                // '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]|[^\x00-\x7F])*)' . -> seems to be taking too much
2486
                // '/(((([A-Za-z_:])([^\x00-\x7F])*)' . -> takes only last letter of parameter name
2487
                '([ \n\t\r]+)?('.
2488
                // '(=([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+))' . -> doesn't restrict close enough to the url itself
2489
                '(=([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+))'.
2490
                '|'.
2491
                // '(\(([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)\))' . -> doesn't restrict close enough to the url itself
2492
                '(\(([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+)\))'.
2493
                '))'.
2494
                '|'.
2495
                // '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))?/', -> takes a lot (like 100's of thousands of empty possibilities)
2496
                '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))/',
2497
                $attrString,
2498
                $regs
2499
            );
2500
        } catch (Exception $e) {
2501
            error_log('Caught exception: '.$e->getMessage(), 0);
2502
        }
2503
        if ($res) {
2504
            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...
2505
                $name = trim($regs[3][$i]);
2506
                $check = trim($regs[0][$i]);
2507
                $value = trim($regs[10][$i]);
2508
                if (empty($value) and !empty($regs[13][$i])) {
2509
                    $value = $regs[13][$i];
2510
                }
2511
                if (empty($name) && !empty($regs[16][$i])) {
2512
                    $name = '@import';
2513
                    $value = trim($regs[16][$i]);
2514
                }
2515
                if (!empty($name)) {
2516
                    if (!$reduced || in_array(strtolower($name), $wanted)) {
2517
                        if ($name == $check) {
2518
                            $attributes[strtolower($name)][] = strtolower($name);
2519
                        } else {
2520
                            if (!empty($value) && ($value[0] == '\'' || $value[0] == '"')) {
2521
                                $value = substr($value, 1, -1);
2522
                            }
2523
2524
                            if ($value == 'API.LMSGetValue(name') {
2525
                                $value = 'API.LMSGetValue(name)';
2526
                            }
2527
                            //Gets the xx.flv value from the string flashvars="width=320&height=240&autostart=false&file=xxx.flv&repeat=false"
2528
                            if (isset($explode_variables[$name])) {
2529
                                $value_modified = str_replace('&amp;', '&', $value);
2530
                                $value_array = explode('&', $value_modified);
2531
                                foreach ($value_array as $item) {
2532
                                    $itemParts = explode('=', $item);
2533
                                    $key = $itemParts[0];
2534
                                    $item_value = !empty($itemParts[1]) ? $itemParts[1] : '';
2535
                                    if ($key == $explode_variables[$name]) {
2536
                                        $attributes[strtolower($name)][] = $item_value;
2537
                                    }
2538
                                }
2539
                            }
2540
                            $attributes[strtolower($name)][] = $value;
2541
                        }
2542
                    }
2543
                }
2544
            }
2545
        }
2546
2547
        return $attributes;
2548
    }
2549
2550
    /**
2551
     * Replace urls inside content html from a copy course.
2552
     *
2553
     * @param string $content_html
2554
     * @param string $origin_course_code
2555
     * @param string $destination_course_directory
2556
     * @param string $origin_course_path_from_zip
2557
     * @param string $origin_course_info_path
2558
     *
2559
     * @return string new content html with replaced urls or return false if content is not a string
2560
     */
2561
    public static function replaceUrlWithNewCourseCode(
2562
        $content_html,
2563
        $origin_course_code,
2564
        $destination_course_directory,
2565
        $origin_course_path_from_zip = null,
2566
        $origin_course_info_path = null
2567
    ) {
2568
        if (empty($content_html)) {
2569
            return false;
2570
        }
2571
2572
        $orig_source_html = self::get_resources_from_source_html($content_html);
2573
        $orig_course_info = api_get_course_info($origin_course_code);
2574
2575
        // Course does not exist in the current DB probably this came from a zip file?
2576
        if (empty($orig_course_info)) {
2577
            if (!empty($origin_course_path_from_zip)) {
2578
                $orig_course_path = $origin_course_path_from_zip.'/';
2579
                $orig_course_info_path = $origin_course_info_path;
2580
            }
2581
        } else {
2582
            $orig_course_path = api_get_path(SYS_COURSE_PATH).$orig_course_info['path'].'/';
2583
            $orig_course_info_path = $orig_course_info['path'];
2584
        }
2585
2586
        $destination_course_code = CourseManager::getCourseCodeFromDirectory($destination_course_directory);
2587
        $destination_course_info = api_get_course_info($destination_course_code);
2588
        $dest_course_path = api_get_path(SYS_COURSE_PATH).$destination_course_directory.'/';
2589
        $dest_course_path_rel = api_get_path(REL_COURSE_PATH).$destination_course_directory.'/';
2590
2591
        $user_id = api_get_user_id();
2592
2593
        if (!empty($orig_source_html)) {
2594
            foreach ($orig_source_html as $source) {
2595
                // Get information about source url
2596
                $real_orig_url = $source[0]; // url
2597
                $scope_url = $source[1]; // scope (local, remote)
2598
                $type_url = $source[2]; // type (rel, abs, url)
2599
2600
                // Get path and query from origin url
2601
                $orig_parse_url = parse_url($real_orig_url);
2602
                $real_orig_path = isset($orig_parse_url['path']) ? $orig_parse_url['path'] : null;
2603
                $real_orig_query = isset($orig_parse_url['query']) ? $orig_parse_url['query'] : null;
2604
2605
                // Replace origin course code by destination course code from origin url query
2606
                $dest_url_query = '';
2607
2608
                if (!empty($real_orig_query)) {
2609
                    $dest_url_query = '?'.$real_orig_query;
2610
                    if (strpos($dest_url_query, $origin_course_code) !== false) {
2611
                        $dest_url_query = str_replace($origin_course_code, $destination_course_code, $dest_url_query);
2612
                    }
2613
                }
2614
2615
                if ($scope_url == 'local') {
2616
                    if ($type_url == 'abs' || $type_url == 'rel') {
2617
                        $document_file = strstr($real_orig_path, 'document');
2618
2619
                        if (strpos($real_orig_path, $document_file) !== false) {
2620
                            $origin_filepath = $orig_course_path.$document_file;
2621
                            $destination_filepath = $dest_course_path.$document_file;
2622
2623
                            // copy origin file inside destination course
2624
                            if (file_exists($origin_filepath)) {
2625
                                $filepath_dir = dirname($destination_filepath);
2626
2627
                                if (!is_dir($filepath_dir)) {
2628
                                    $perm = api_get_permissions_for_new_directories();
2629
                                    $result = @mkdir($filepath_dir, $perm, true);
2630
                                    if ($result) {
2631
                                        $filepath_to_add = str_replace(
2632
                                            [$dest_course_path, 'document'],
2633
                                            '',
2634
                                            $filepath_dir
2635
                                        );
2636
2637
                                        //Add to item properties to the new folder
2638
                                        $doc_id = add_document(
2639
                                            $destination_course_info,
2640
                                            $filepath_to_add,
2641
                                            'folder',
2642
                                            0,
2643
                                            basename($filepath_to_add)
2644
                                        );
2645
                                        api_item_property_update(
2646
                                            $destination_course_info,
2647
                                            TOOL_DOCUMENT,
2648
                                            $doc_id,
2649
                                            'FolderCreated',
2650
                                            $user_id,
2651
                                            null,
2652
                                            null,
2653
                                            null,
2654
                                            null
2655
                                        );
2656
                                    }
2657
                                }
2658
2659
                                if (!file_exists($destination_filepath)) {
2660
                                    $result = @copy($origin_filepath, $destination_filepath);
2661
                                    if ($result) {
2662
                                        $filepath_to_add = str_replace(
2663
                                            [$dest_course_path, 'document'],
2664
                                            '',
2665
                                            $destination_filepath
2666
                                        );
2667
                                        $size = filesize($destination_filepath);
2668
2669
                                        // Add to item properties to the file
2670
                                        $doc_id = add_document(
2671
                                            $destination_course_info,
2672
                                            $filepath_to_add,
2673
                                            'file',
2674
                                            $size,
2675
                                            basename($filepath_to_add)
2676
                                        );
2677
                                        api_item_property_update(
2678
                                            $destination_course_info,
2679
                                            TOOL_DOCUMENT,
2680
                                            $doc_id,
2681
                                            'FolderCreated',
2682
                                            $user_id,
2683
                                            null,
2684
                                            null,
2685
                                            null,
2686
                                            null
2687
                                        );
2688
                                    }
2689
                                }
2690
                            }
2691
2692
                            // Replace origin course path by destination course path.
2693
                            if (strpos($content_html, $real_orig_url) !== false) {
2694
                                $url_course_path = str_replace(
2695
                                    $orig_course_info_path.'/'.$document_file,
2696
                                    '',
2697
                                    $real_orig_path
2698
                                );
2699
                                // See BT#7780
2700
                                $destination_url = $dest_course_path_rel.$document_file.$dest_url_query;
2701
                                // If the course code doesn't exist in the path? what we do? Nothing! see BT#1985
2702
                                if (strpos($real_orig_path, $origin_course_code) === false) {
2703
                                    $url_course_path = $real_orig_path;
2704
                                    $destination_url = $real_orig_path;
2705
                                }
2706
                                $content_html = str_replace($real_orig_url, $destination_url, $content_html);
2707
                            }
2708
                        }
2709
2710
                        // replace origin course code by destination course code  from origin url
2711
                        if (strpos($real_orig_url, '?') === 0) {
2712
                            $dest_url = str_replace($origin_course_code, $destination_course_code, $real_orig_url);
2713
                            $content_html = str_replace($real_orig_url, $dest_url, $content_html);
2714
                        }
2715
                    }
2716
                }
2717
            }
2718
        }
2719
2720
        return $content_html;
2721
    }
2722
2723
    /**
2724
     * Export document to PDF.
2725
     *
2726
     * @param int    $document_id
2727
     * @param string $courseCode
2728
     * @param string $orientation
2729
     * @param bool   $showHeaderAndFooter
2730
     */
2731
    public static function export_to_pdf(
2732
        $document_id,
2733
        $courseCode,
2734
        $orientation = 'landscape',
2735
        $showHeaderAndFooter = true
2736
    ) {
2737
        $course_data = api_get_course_info($courseCode);
2738
        $document_data = self::get_document_data_by_id($document_id, $courseCode);
2739
        $file_path = api_get_path(SYS_COURSE_PATH).$course_data['path'].'/document'.$document_data['path'];
2740
        if ($orientation == 'landscape') {
2741
            $pageFormat = 'A4-L';
2742
            $pdfOrientation = 'L';
2743
        } else {
2744
            $pageFormat = 'A4';
2745
            $pdfOrientation = 'P';
2746
        }
2747
        $pdf = new PDF(
2748
            $pageFormat,
2749
            $pdfOrientation,
2750
            $showHeaderAndFooter ? [] : ['top' => 0, 'left' => 0, 'bottom' => 0, 'right' => 0]
2751
        );
2752
2753
        if (api_get_configuration_value('use_alternative_document_pdf_footer')) {
2754
            $view = new Template('', false, false, false, true, false, false);
2755
            $template = $view->get_template('export/alt_pdf_footer.tpl');
2756
2757
            $pdf->set_custom_footer([
2758
                'html' => $view->fetch($template),
2759
            ]);
2760
        }
2761
2762
        $pdf->html_to_pdf(
2763
            $file_path,
2764
            $document_data['title'],
2765
            $courseCode,
2766
            false,
2767
            $showHeaderAndFooter
2768
        );
2769
    }
2770
2771
    /**
2772
     * Uploads a document.
2773
     *
2774
     * @param array  $files                   the $_FILES variable
2775
     * @param string $path
2776
     * @param string $title
2777
     * @param string $comment
2778
     * @param int    $unzip                   unzip or not the file
2779
     * @param string $ifExists                overwrite, rename or warn (default)
2780
     * @param bool   $index_document          index document (search xapian module)
2781
     * @param bool   $show_output             print html messages
2782
     * @param string $fileKey
2783
     * @param bool   $treat_spaces_as_hyphens
2784
     *
2785
     * @return array|bool
2786
     */
2787
    public static function upload_document(
2788
        $files,
2789
        $path,
2790
        $title = '',
2791
        $comment = '',
2792
        $unzip = 0,
2793
        $ifExists = '',
2794
        $index_document = false,
2795
        $show_output = false,
2796
        $fileKey = 'file',
2797
        $treat_spaces_as_hyphens = true
2798
    ) {
2799
        $course_info = api_get_course_info();
2800
        $sessionId = api_get_session_id();
2801
        $course_dir = $course_info['path'].'/document';
2802
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
2803
        $base_work_dir = $sys_course_path.$course_dir;
2804
2805
        if (isset($files[$fileKey])) {
2806
            $uploadOk = process_uploaded_file($files[$fileKey], $show_output);
2807
            if ($uploadOk) {
2808
                $new_path = handle_uploaded_document(
2809
                    $course_info,
2810
                    $files[$fileKey],
2811
                    $base_work_dir,
2812
                    $path,
2813
                    api_get_user_id(),
2814
                    api_get_group_id(),
2815
                    null,
2816
                    $unzip,
2817
                    $ifExists,
2818
                    $show_output,
2819
                    false,
2820
                    null,
2821
                    $sessionId,
2822
                    $treat_spaces_as_hyphens
2823
                );
2824
2825
                // Showing message when sending zip files
2826
                if ($new_path === true && $unzip == 1) {
2827
                    if ($show_output) {
2828
                        echo Display::return_message(
2829
                            get_lang('UplUploadSucceeded').'<br />',
2830
                            'confirm',
2831
                            false
2832
                        );
2833
                    }
2834
2835
                    return [
2836
                        'title' => $files[$fileKey]['name'],
2837
                        'url' => '#',
2838
                    ];
2839
                }
2840
2841
                if ($new_path) {
2842
                    $documentId = self::get_document_id(
2843
                        $course_info,
2844
                        $new_path,
2845
                        $sessionId
2846
                    );
2847
2848
                    if (!empty($documentId)) {
2849
                        $table_document = Database::get_course_table(TABLE_DOCUMENT);
2850
                        $params = [];
2851
2852
                        if (!empty($title)) {
2853
                            $params['title'] = $title;
2854
                        }
2855
2856
                        if (!empty($comment)) {
2857
                            $params['comment'] = trim($comment);
2858
                        }
2859
2860
                        Database::update(
2861
                            $table_document,
2862
                            $params,
2863
                            [
2864
                                'id = ? AND c_id = ? ' => [
2865
                                    $documentId,
2866
                                    $course_info['real_id'],
2867
                                ],
2868
                            ]
2869
                        );
2870
                    }
2871
2872
                    if ($index_document) {
2873
                        self::index_document(
2874
                            $documentId,
2875
                            $course_info['code'],
2876
                            null,
2877
                            $_POST['language'],
2878
                            $_REQUEST,
2879
                            $ifExists
2880
                        );
2881
                    }
2882
2883
                    if (!empty($documentId) && is_numeric($documentId)) {
2884
                        $documentData = self::get_document_data_by_id(
2885
                            $documentId,
2886
                            $course_info['code'],
2887
                            false,
2888
                            $sessionId
2889
                        );
2890
2891
                        return $documentData;
2892
                    }
2893
                }
2894
            }
2895
        }
2896
2897
        return false;
2898
    }
2899
2900
    /**
2901
     * Obtains the text inside the file with the right parser.
2902
     */
2903
    public static function get_text_content($doc_path, $doc_mime)
2904
    {
2905
        // TODO: review w$ compatibility
2906
        // Use usual exec output lines array to store stdout instead of a temp file
2907
        // because we need to store it at RAM anyway before index on ChamiloIndexer object
2908
        $ret_val = null;
2909
        switch ($doc_mime) {
2910
            case 'text/plain':
2911
                $handle = fopen($doc_path, 'r');
2912
                $output = [fread($handle, filesize($doc_path))];
2913
                fclose($handle);
2914
                break;
2915
            case 'application/pdf':
2916
                exec("pdftotext $doc_path -", $output, $ret_val);
2917
                break;
2918
            case 'application/postscript':
2919
                $temp_file = tempnam(sys_get_temp_dir(), 'chamilo');
2920
                exec("ps2pdf $doc_path $temp_file", $output, $ret_val);
2921
                if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
2922
                    return false;
2923
                }
2924
                exec("pdftotext $temp_file -", $output, $ret_val);
2925
                unlink($temp_file);
2926
                break;
2927
            case 'application/msword':
2928
                exec("catdoc $doc_path", $output, $ret_val);
2929
                break;
2930
            case 'text/html':
2931
                exec("html2text $doc_path", $output, $ret_val);
2932
                break;
2933
            case 'text/rtf':
2934
                // Note: correct handling of code pages in unrtf
2935
                // on debian lenny unrtf v0.19.2 can not, but unrtf v0.20.5 can
2936
                exec("unrtf --text $doc_path", $output, $ret_val);
2937
                if ($ret_val == 127) { // command not found
2938
                    return false;
2939
                }
2940
                // Avoid index unrtf comments
2941
                if (is_array($output) && count($output) > 1) {
2942
                    $parsed_output = [];
2943
                    foreach ($output as &$line) {
2944
                        if (!preg_match('/^###/', $line, $matches)) {
2945
                            if (!empty($line)) {
2946
                                $parsed_output[] = $line;
2947
                            }
2948
                        }
2949
                    }
2950
                    $output = $parsed_output;
2951
                }
2952
                break;
2953
            case 'application/vnd.ms-powerpoint':
2954
                exec("catppt $doc_path", $output, $ret_val);
2955
                break;
2956
            case 'application/vnd.ms-excel':
2957
                exec("xls2csv -c\" \" $doc_path", $output, $ret_val);
2958
                break;
2959
        }
2960
2961
        $content = '';
2962
        if (!is_null($ret_val)) {
2963
            if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
2964
                return false;
2965
            }
2966
        }
2967
        if (isset($output)) {
2968
            foreach ($output as &$line) {
2969
                $content .= $line."\n";
2970
            }
2971
2972
            return $content;
2973
        } else {
2974
            return false;
2975
        }
2976
    }
2977
2978
    /**
2979
     * Calculates the total size of all documents in a course.
2980
     *
2981
     * @author Bert vanderkimpen
2982
     *
2983
     * @param int $course_id
2984
     * @param int $group_id   (to calculate group document space)
2985
     * @param int $session_id
2986
     *
2987
     * @return int total size
2988
     */
2989
    public static function documents_total_space($course_id = null, $group_id = null, $session_id = null)
2990
    {
2991
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
2992
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
2993
        $session_id = intval($session_id);
2994
        $group_id = intval($group_id);
2995
        $course_id = intval($course_id);
2996
2997
        if (!$course_id) {
2998
            $course_id = api_get_course_int_id();
2999
        }
3000
3001
        $group_condition = '';
3002
        if ($group_id) {
3003
            $group_condition = " AND props.to_group_id='".$group_id."' ";
3004
        }
3005
3006
        $session_condition = '';
3007
        if ($session_id) {
3008
            $session_condition = " AND props.session_id='".$session_id."' ";
3009
        }
3010
3011
        $sql = "SELECT SUM(size)
3012
                FROM $TABLE_ITEMPROPERTY AS props
3013
                INNER JOIN $TABLE_DOCUMENT AS docs
3014
                ON (docs.id = props.ref AND props.c_id = docs.c_id)
3015
                WHERE
3016
                    props.c_id 	= $course_id AND
3017
                    docs.c_id 	= $course_id AND
3018
                    props.tool 	= '".TOOL_DOCUMENT."' AND
3019
                    props.visibility <> 2
3020
                    $group_condition
3021
                    $session_condition
3022
                ";
3023
        $result = Database::query($sql);
3024
3025
        if ($result && Database::num_rows($result) != 0) {
3026
            $row = Database::fetch_row($result);
3027
3028
            return $row[0];
3029
        } else {
3030
            return 0;
3031
        }
3032
    }
3033
3034
    /**
3035
     * Display the document quota in a simple way.
3036
     *
3037
     *  Here we count 1 Kilobyte = 1024 Bytes, 1 Megabyte = 1048576 Bytes
3038
     */
3039
    public static function displaySimpleQuota($course_quota, $already_consumed_space)
3040
    {
3041
        $course_quota_m = round($course_quota / 1048576);
3042
        $already_consumed_space_m = round($already_consumed_space / 1048576, 2);
3043
        $percentage = $already_consumed_space / $course_quota * 100;
3044
        $percentage = round($percentage, 1);
3045
        $message = get_lang('YouAreCurrentlyUsingXOfYourX');
3046
        $message = sprintf($message, $already_consumed_space_m, $percentage.'%', $course_quota_m.' ');
3047
3048
        return Display::div($message, ['id' => 'document_quota']);
3049
    }
3050
3051
    /**
3052
     * Checks if there is enough place to add a file on a directory
3053
     * on the base of a maximum directory size allowed.
3054
     *
3055
     * @author Bert Vanderkimpen
3056
     *
3057
     * @param int $file_size     size of the file in byte
3058
     * @param int $max_dir_space maximum size
3059
     *
3060
     * @return bool true if there is enough space, false otherwise
3061
     *
3062
     * @see enough_space() uses  documents_total_space() function
3063
     */
3064
    public static function enough_space($file_size, $max_dir_space)
3065
    {
3066
        if ($max_dir_space) {
3067
            $already_filled_space = self::documents_total_space();
3068
            if (($file_size + $already_filled_space) > $max_dir_space) {
3069
                return false;
3070
            }
3071
        }
3072
3073
        return true;
3074
    }
3075
3076
    /**
3077
     * @param array $params count, url, extension
3078
     *
3079
     * @return string
3080
     */
3081
    public static function generateAudioJavascript($params = [])
3082
    {
3083
        $js = '
3084
            $(\'audio.audio_preview\').mediaelementplayer({
3085
                features: [\'playpause\'],
3086
                audioWidth: 30,
3087
                audioHeight: 30,
3088
                success: function(mediaElement, originalNode, instance) {                
3089
                }
3090
            });';
3091
3092
        return $js;
3093
    }
3094
3095
    /**
3096
     * Shows a play icon next to the document title in the document list.
3097
     *
3098
     * @param string $documentWebPath
3099
     * @param array  $documentInfo
3100
     *
3101
     * @return string
3102
     */
3103
    public static function generateAudioPreview($documentWebPath, $documentInfo)
3104
    {
3105
        $filePath = $documentWebPath.$documentInfo['path'];
3106
        $extension = $documentInfo['file_extension'];
3107
        $html = '<span class="preview"> <audio class="audio_preview skip" src="'.$filePath.'" type="audio/'.$extension.'" > </audio></span>';
3108
3109
        return $html;
3110
    }
3111
3112
    /**
3113
     * @param string $file
3114
     * @param string $extension
3115
     *
3116
     * @return string
3117
     */
3118
    public static function generateVideoPreview($file, $extension)
3119
    {
3120
        $type = '';
3121
        /*if ($extension != 'flv') {
3122
3123
        }*/
3124
        //$type = "video/$extension";
3125
        $html = '<video id="myvideo"  src="'.$file.'" controls '.$type.'">';
3126
3127
        return $html;
3128
    }
3129
3130
    /**
3131
     * @param array  $course_info
3132
     * @param bool   $lp_id
3133
     * @param string $target
3134
     * @param int    $session_id
3135
     * @param bool   $add_move_button
3136
     * @param string $filter_by_folder
3137
     * @param string $overwrite_url
3138
     * @param bool   $showInvisibleFiles
3139
     * @param bool   $showOnlyFolders
3140
     * @param int    $folderId
3141
     *
3142
     * @return string
3143
     */
3144
    public static function get_document_preview(
3145
        $course_info,
3146
        $lp_id = false,
3147
        $target = '',
3148
        $session_id = 0,
3149
        $add_move_button = false,
3150
        $filter_by_folder = null,
3151
        $overwrite_url = '',
3152
        $showInvisibleFiles = false,
3153
        $showOnlyFolders = false,
3154
        $folderId = false
3155
    ) {
3156
        if (empty($course_info['real_id']) || empty($course_info['code']) || !is_array($course_info)) {
3157
            return '';
3158
        }
3159
3160
        $user_id = api_get_user_id();
3161
        $userInfo = api_get_user_info();
3162
3163
        $user_in_course = false;
3164
        if (api_is_platform_admin()) {
3165
            $user_in_course = true;
3166
        }
3167
3168
        if (!$user_in_course) {
3169
            if (CourseManager::is_course_teacher($user_id, $course_info['code'])) {
3170
                $user_in_course = true;
3171
            }
3172
        }
3173
3174
        // Condition for the session
3175
        $session_id = intval($session_id);
3176
3177
        if (!$user_in_course) {
3178
            if (empty($session_id)) {
3179
                if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code'])) {
3180
                    $user_in_course = true;
3181
                }
3182
                // Check if course is open then we can consider that the student is registered to the course
3183
                if (isset($course_info) && in_array($course_info['visibility'], [2, 3])) {
3184
                    $user_in_course = true;
3185
                }
3186
            } else {
3187
                $user_status = SessionManager::get_user_status_in_course_session(
3188
                    $user_id,
3189
                    $course_info['real_id'],
3190
                    $session_id
3191
                );
3192
                //is true if is an student, course session teacher or coach
3193
                if (in_array($user_status, ['0', '2', '6'])) {
3194
                    $user_in_course = true;
3195
                }
3196
            }
3197
        }
3198
3199
        $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
3200
        $tbl_item_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
3201
        $condition_session = " AND (last.session_id = '$session_id' OR last.session_id = '0' OR last.session_id IS NULL)";
3202
3203
        $add_folder_filter = null;
3204
        if (!empty($filter_by_folder)) {
3205
            $add_folder_filter = " AND docs.path LIKE '".Database::escape_string($filter_by_folder)."%'";
3206
        }
3207
3208
        // If we are in LP display hidden folder https://support.chamilo.org/issues/6679
3209
        $lp_visibility_condition = null;
3210
        if ($lp_id) {
3211
            // $lp_visibility_condition = " OR filetype='folder'";
3212
            if ($showInvisibleFiles) {
3213
                $lp_visibility_condition .= ' OR last.visibility = 0';
3214
            }
3215
        }
3216
3217
        $showOnlyFoldersCondition = null;
3218
        if ($showOnlyFolders) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3219
            //$showOnlyFoldersCondition = " AND docs.filetype = 'folder' ";
3220
        }
3221
3222
        $folderCondition = " AND docs.path LIKE '/%' ";
3223
3224
        if (!api_is_allowed_to_edit()) {
3225
            $protectedFolders = self::getProtectedFolderFromStudent();
3226
            foreach ($protectedFolders as $folder) {
3227
                $folderCondition .= " AND docs.path NOT LIKE '$folder' ";
3228
            }
3229
        }
3230
3231
        $parentData = [];
3232
        if ($folderId !== false) {
3233
            $parentData = self::get_document_data_by_id(
3234
                $folderId,
3235
                $course_info['code'],
3236
                false,
3237
                $session_id
3238
            );
3239
            if (!empty($parentData)) {
3240
                $cleanedPath = $parentData['path'];
3241
                $num = substr_count($cleanedPath, '/');
3242
3243
                $notLikeCondition = '';
3244
                for ($i = 1; $i <= $num; $i++) {
3245
                    $repeat = str_repeat('/%', $i + 1);
3246
                    $notLikeCondition .= " AND docs.path NOT LIKE '".Database::escape_string($cleanedPath.$repeat)."' ";
3247
                }
3248
3249
                $folderId = (int) $folderId;
3250
                $folderCondition = " AND
3251
                    docs.id <> $folderId AND
3252
                    docs.path LIKE '".$cleanedPath."/%'
3253
                    $notLikeCondition
3254
                ";
3255
            } else {
3256
                $folderCondition = " AND docs.filetype = 'file' ";
3257
            }
3258
        }
3259
3260
        $levelCondition = null;
3261
        if ($folderId === false) {
3262
            $levelCondition = " AND docs.path NOT LIKE'/%/%'";
3263
        }
3264
3265
        $sql = "SELECT DISTINCT last.visibility, docs.*
3266
                FROM $tbl_item_prop AS last 
3267
                INNER JOIN $tbl_doc AS docs
3268
                ON (docs.id = last.ref AND docs.c_id = last.c_id)
3269
                WHERE
3270
                    docs.path NOT LIKE '%_DELETED_%' AND
3271
                    last.tool = '".TOOL_DOCUMENT."' $condition_session AND
3272
                    (last.visibility = '1' $lp_visibility_condition) AND
3273
                    last.visibility <> 2 AND
3274
                    docs.c_id = {$course_info['real_id']} AND
3275
                    last.c_id = {$course_info['real_id']}
3276
                    $showOnlyFoldersCondition
3277
                    $folderCondition
3278
                    $levelCondition
3279
                    $add_folder_filter
3280
                ORDER BY docs.filetype DESC, docs.title ASC";
3281
3282
        $res_doc = Database::query($sql);
3283
        $resources = Database::store_result($res_doc, 'ASSOC');
3284
3285
        $return = '';
3286
        if ($lp_id) {
3287
            if ($folderId === false) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3288
                /*$return .= '<div class="lp_resource_element">';
3289
                $return .= Display::return_icon('new_doc.gif', '', [], ICON_SIZE_SMALL);
3290
                $return .= Display::url(
3291
                    get_lang('CreateTheDocument'),
3292
                    api_get_self().'?'.api_get_cidreq().'&action=add_item&type='.TOOL_DOCUMENT.'&lp_id='.$_SESSION['oLP']->lp_id
3293
                );
3294
                $return .= '</div>';*/
3295
            }
3296
        } else {
3297
            $return .= Display::div(
3298
                Display::url(
3299
                    Display::return_icon('close.png', get_lang('Close'), [], ICON_SIZE_SMALL),
3300
                    ' javascript:void(0);',
3301
                    ['id' => 'close_div_'.$course_info['real_id'].'_'.$session_id, 'class' => 'close_div']
3302
                ),
3303
                ['style' => 'position:absolute;right:10px']
3304
            );
3305
        }
3306
3307
        // If you want to debug it, I advise you to do "echo" on the eval statements.
3308
        $newResources = [];
3309
        if (!empty($resources) && $user_in_course) {
3310
            foreach ($resources as $resource) {
3311
                $is_visible = self::is_visible_by_id(
3312
                    $resource['id'],
3313
                    $course_info,
3314
                    $session_id,
3315
                    api_get_user_id()
3316
                );
3317
3318
                if ($showInvisibleFiles == false) {
3319
                    if (!$is_visible) {
3320
                        continue;
3321
                    }
3322
                }
3323
3324
                $newResources[] = $resource;
3325
            }
3326
        }
3327
3328
        $label = get_lang('Documents');
3329
3330
        $documents = [];
3331
        if ($folderId === false) {
3332
            $documents[$label] = [
3333
                'id' => 0,
3334
                'files' => $newResources,
3335
            ];
3336
        } else {
3337
            if (is_array($parentData)) {
3338
                $documents[$parentData['title']] = [
3339
                    'id' => intval($folderId),
3340
                    'files' => $newResources,
3341
                ];
3342
            }
3343
        }
3344
3345
        $write_result = self::write_resources_tree(
3346
            $userInfo,
3347
            $course_info,
3348
            $session_id,
3349
            $documents,
3350
            $lp_id,
3351
            $target,
3352
            $add_move_button,
3353
            $overwrite_url,
3354
            $folderId
3355
        );
3356
3357
        $return .= $write_result;
3358
        if ($lp_id == false) {
3359
            $url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?a=get_documents&url='.$overwrite_url.'&lp_id='.$lp_id.'&cidReq='.$course_info['code'];
3360
            $return .= "<script>
3361
            $('.doc_folder').click(function() {
3362
                var realId = this.id;
3363
                var my_id = this.id.split('_')[2];
3364
                var tempId = 'temp_'+my_id;
3365
                $('#res_'+my_id).show();
3366
3367
                var tempDiv = $('#'+realId).find('#'+tempId);
3368
                if (tempDiv.length == 0) {
3369
                    $.ajax({
3370
                        async: false,
3371
                        type: 'GET',
3372
                        url:  '".$url."',
3373
                        data: 'folder_id='+my_id,
3374
                        success: function(data) {
3375
                            $('#'+realId).append('<div id='+tempId+'>'+data+'</div>');
3376
                        }
3377
                    });
3378
                }
3379
            });
3380
3381
            $('.close_div').click(function() {
3382
                var course_id = this.id.split('_')[2];
3383
                var session_id = this.id.split('_')[3];
3384
                $('#document_result_'+course_id+'_'+session_id).hide();
3385
                $('.lp_resource').remove();
3386
                $('.document_preview_container').html('');
3387
            });
3388
3389
            </script>";
3390
        } else {
3391
            //For LPs
3392
            $url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?a=get_documents&lp_id='.$lp_id.'&'.api_get_cidreq();
3393
            $return .= "<script>
3394
3395
            function testResources(id, img) {
3396
                var numericId = id.split('_')[1];
3397
                var parentId = 'doc_id_'+numericId;
3398
                var tempId = 'temp_'+numericId;
3399
                var image = $('#'+img);
3400
3401
                if (image.hasClass('open')) {
3402
                    image.removeClass('open');
3403
                    image.attr('src', '".Display::returnIconPath('nolines_plus.gif')."');
3404
                    $('#'+id).show();
3405
                    $('#'+tempId).hide();
3406
                } else {
3407
                    image.addClass('open');
3408
                    image.attr('src', '".Display::returnIconPath('nolines_minus.gif')."');
3409
                    $('#'+id).hide();
3410
                    $('#'+tempId).show();
3411
3412
                    var tempDiv = $('#'+parentId).find('#'+tempId);
3413
                    if (tempDiv.length == 0) {
3414
                        $.ajax({
3415
                            type: 'GET',
3416
                            async: false,
3417
                            url:  '".$url."',
3418
                            data: 'folder_id='+numericId,
3419
                            success: function(data) {
3420
                                tempDiv = $('#doc_id_'+numericId).append('<div id='+tempId+'>'+data+'</div>');
3421
                            }
3422
                        });
3423
                    }
3424
                }
3425
            }
3426
            </script>";
3427
        }
3428
3429
        if (!$user_in_course) {
3430
            $return = '';
3431
        }
3432
3433
        return $return;
3434
    }
3435
3436
    /**
3437
     * Generate and return an HTML list of resources based on a given array.
3438
     * This list is used to show the course creator a list of available resources to choose from
3439
     * when creating a learning path.
3440
     *
3441
     * @param array  $userInfo        current user info
3442
     * @param array  $course_info
3443
     * @param int    $session_id
3444
     * @param array  $documents
3445
     * @param bool   $lp_id
3446
     * @param string $target
3447
     * @param bool   $add_move_button
3448
     * @param string $overwrite_url
3449
     * @param int    $folderId
3450
     *
3451
     * @return string
3452
     */
3453
    public static function write_resources_tree(
3454
        $userInfo,
3455
        $course_info,
3456
        $session_id,
3457
        $documents,
3458
        $lp_id = false,
3459
        $target = '',
3460
        $add_move_button = false,
3461
        $overwrite_url = '',
3462
        $folderId = false
3463
    ) {
3464
        $return = '';
3465
        if (!empty($documents)) {
3466
            foreach ($documents as $key => $resource) {
3467
                if (isset($resource['id']) && is_int($resource['id'])) {
3468
                    $mainFolderResource = [
3469
                        'id' => $resource['id'],
3470
                        'title' => $key,
3471
                    ];
3472
3473
                    if ($folderId === false) {
3474
                        $return .= self::parseFolder($folderId, $mainFolderResource, $lp_id);
3475
                    }
3476
3477
                    if (isset($resource['files'])) {
3478
                        $return .= self::write_resources_tree(
3479
                            $userInfo,
3480
                            $course_info,
3481
                            $session_id,
3482
                            $resource['files'],
3483
                            $lp_id,
3484
                            $target,
3485
                            $add_move_button,
3486
                            $overwrite_url
3487
                        );
3488
                    }
3489
                    $return .= '</div>';
3490
                    $return .= '</ul>';
3491
                } else {
3492
                    if ($resource['filetype'] == 'folder') {
3493
                        $return .= self::parseFolder($folderId, $resource, $lp_id);
3494
                    } else {
3495
                        $return .= self::parseFile(
3496
                            $userInfo,
3497
                            $course_info,
3498
                            $session_id,
3499
                            $resource,
3500
                            $lp_id,
3501
                            $add_move_button,
3502
                            $target,
3503
                            $overwrite_url
3504
                        );
3505
                    }
3506
                }
3507
            }
3508
        }
3509
3510
        return $return;
3511
    }
3512
3513
    /**
3514
     * @param int    $doc_id
3515
     * @param string $course_code
3516
     * @param int    $session_id
3517
     * @param int    $user_id
3518
     * @param int    $groupId     iid
3519
     *
3520
     * @return bool
3521
     */
3522
    public static function check_visibility_tree(
3523
        $doc_id,
3524
        $course_code,
3525
        $session_id,
3526
        $user_id,
3527
        $groupId = 0
3528
    ) {
3529
        $document_data = self::get_document_data_by_id(
3530
            $doc_id,
3531
            $course_code,
3532
            null,
3533
            $session_id
3534
        );
3535
        if ($session_id != 0 && !$document_data) {
3536
            $document_data = self::get_document_data_by_id(
3537
                $doc_id,
3538
                $course_code,
3539
                null,
3540
                0
3541
            );
3542
        }
3543
3544
        if (!empty($document_data)) {
3545
            // If admin or course teacher, allow anyway
3546
            if (api_is_platform_admin() || CourseManager::is_course_teacher($user_id, $course_code)) {
3547
                return true;
3548
            }
3549
            $course_info = api_get_course_info($course_code);
3550
            if ($document_data['parent_id'] == false || empty($document_data['parent_id'])) {
3551
                if (!empty($groupId)) {
3552
                    return true;
3553
                }
3554
                $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
3555
3556
                return $visible;
3557
            } else {
3558
                $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
3559
3560
                if (!$visible) {
3561
                    return false;
3562
                } else {
3563
                    return self::check_visibility_tree(
3564
                        $document_data['parent_id'],
3565
                        $course_code,
3566
                        $session_id,
3567
                        $user_id,
3568
                        $groupId
3569
                    );
3570
                }
3571
            }
3572
        } else {
3573
            return false;
3574
        }
3575
    }
3576
3577
    /**
3578
     * Index a given document.
3579
     *
3580
     * @param   int     Document ID inside its corresponding course
3581
     * @param   string  Course code
3582
     * @param   int     Session ID (not used yet)
3583
     * @param   string  Language of document's content (defaults to course language)
3584
     * @param   array   Array of specific fields (['code'=>'value',...])
3585
     * @param   string  What to do if the file already exists (default or overwrite)
3586
     * @param   bool    When set to true, this runs the indexer without actually saving anything to any database
3587
     *
3588
     * @return bool Returns true on presumed success, false on failure
3589
     */
3590
    public static function index_document(
3591
        $docid,
3592
        $course_code,
3593
        $session_id = 0,
3594
        $lang = 'english',
3595
        $specific_fields_values = [],
3596
        $if_exists = '',
3597
        $simulation = false
3598
    ) {
3599
        if (api_get_setting('search_enabled') !== 'true') {
3600
            return false;
3601
        }
3602
        if (empty($docid) or $docid != intval($docid)) {
3603
            return false;
3604
        }
3605
        if (empty($session_id)) {
3606
            $session_id = api_get_session_id();
3607
        }
3608
        $course_info = api_get_course_info($course_code);
3609
        $course_dir = $course_info['path'].'/document';
3610
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
3611
        $base_work_dir = $sys_course_path.$course_dir;
3612
3613
        $course_id = $course_info['real_id'];
3614
        $table_document = Database::get_course_table(TABLE_DOCUMENT);
3615
3616
        $qry = "SELECT path, title FROM $table_document WHERE c_id = $course_id AND id = '$docid' LIMIT 1";
3617
        $result = Database::query($qry);
3618
        if (Database::num_rows($result) == 1) {
3619
            $row = Database::fetch_array($result);
3620
            $doc_path = api_get_path(SYS_COURSE_PATH).$course_dir.$row['path'];
3621
            //TODO: mime_content_type is deprecated, fileinfo php extension is enabled by default as of PHP 5.3.0
3622
            // now versions of PHP on Debian testing(5.2.6-5) and Ubuntu(5.2.6-2ubuntu) are lower, so wait for a while
3623
            $doc_mime = mime_content_type($doc_path);
3624
            $allowed_mime_types = self::file_get_mime_type(true);
3625
3626
            // mime_content_type does not detect correctly some formats that
3627
            // are going to be supported for index, so an extensions array is used for the moment
3628
            if (empty($doc_mime)) {
3629
                $allowed_extensions = [
3630
                    'doc',
3631
                    'docx',
3632
                    'ppt',
3633
                    'pptx',
3634
                    'pps',
3635
                    'ppsx',
3636
                    'xls',
3637
                    'xlsx',
3638
                    'odt',
3639
                    'odp',
3640
                    'ods',
3641
                    'pdf',
3642
                    'txt',
3643
                    'rtf',
3644
                    'msg',
3645
                    'csv',
3646
                    'html',
3647
                    'htm',
3648
                ];
3649
                $extensions = preg_split("/[\/\\.]/", $doc_path);
3650
                $doc_ext = strtolower($extensions[count($extensions) - 1]);
3651
                if (in_array($doc_ext, $allowed_extensions)) {
3652
                    switch ($doc_ext) {
3653
                        case 'ppt':
3654
                        case 'pps':
3655
                            $doc_mime = 'application/vnd.ms-powerpoint';
3656
                            break;
3657
                        case 'xls':
3658
                            $doc_mime = 'application/vnd.ms-excel';
3659
                            break;
3660
                    }
3661
                }
3662
            }
3663
3664
            //@todo move this nightmare in a search controller or something like that!!! J.M
3665
3666
            if (in_array($doc_mime, $allowed_mime_types)) {
3667
                $file_title = $row['title'];
3668
                $file_content = self::get_text_content($doc_path, $doc_mime);
3669
                $course_code = Database::escape_string($course_code);
3670
                $ic_slide = new IndexableChunk();
3671
                $ic_slide->addValue('title', $file_title);
3672
                $ic_slide->addCourseId($course_code);
3673
                $ic_slide->addToolId(TOOL_DOCUMENT);
3674
                $xapian_data = [
3675
                    SE_COURSE_ID => $course_code,
3676
                    SE_TOOL_ID => TOOL_DOCUMENT,
3677
                    SE_DATA => ['doc_id' => $docid],
3678
                    SE_USER => api_get_user_id(),
3679
                ];
3680
3681
                $ic_slide->xapian_data = serialize($xapian_data);
3682
                $di = new ChamiloIndexer();
3683
                $return = $di->connectDb(null, null, $lang);
3684
3685
                require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
3686
                $specific_fields = get_specific_field_list();
3687
3688
                // process different depending on what to do if file exists
3689
                /**
3690
                 * @TODO Find a way to really verify if the file had been
3691
                 * overwriten. Now all work is done at
3692
                 * handle_uploaded_document() and it's difficult to verify it
3693
                 */
3694
                if (!empty($if_exists) && $if_exists == 'overwrite') {
3695
                    // Overwrite the file on search engine
3696
                    // Actually, it consists on a delete of terms from db,
3697
                    // insert new ones, create a new search engine document,
3698
                    // and remove the old one
3699
                    // Get search_did
3700
                    $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3701
                    $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
3702
                    $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid);
3703
3704
                    $res = Database::query($sql);
3705
3706
                    if (Database::num_rows($res) > 0) {
3707
                        $se_ref = Database::fetch_array($res);
3708
                        if (!$simulation) {
3709
                            $di->remove_document($se_ref['search_did']);
3710
                        }
3711
                        $all_specific_terms = '';
3712
                        foreach ($specific_fields as $specific_field) {
3713
                            if (!$simulation) {
3714
                                delete_all_specific_field_value($course_code, $specific_field['id'], TOOL_DOCUMENT, $docid);
3715
                            }
3716
                            // Update search engine
3717
                            if (isset($specific_fields_values[$specific_field['code']])) {
3718
                                $sterms = trim($specific_fields_values[$specific_field['code']]);
3719
                            } else { //if the specific field is not defined, force an empty one
3720
                                $sterms = '';
3721
                            }
3722
                            $all_specific_terms .= ' '.$sterms;
3723
                            $sterms = explode(',', $sterms);
3724
                            foreach ($sterms as $sterm) {
3725
                                $sterm = trim($sterm);
3726
                                if (!empty($sterm)) {
3727
                                    $ic_slide->addTerm($sterm, $specific_field['code']);
3728
                                    // updated the last param here from $value to $sterm without being sure - see commit15464
3729
                                    if (!$simulation) {
3730
                                        add_specific_field_value(
3731
                                            $specific_field['id'],
3732
                                            $course_code,
3733
                                            TOOL_DOCUMENT,
3734
                                            $docid,
3735
                                            $sterm
3736
                                        );
3737
                                    }
3738
                                }
3739
                            }
3740
                        }
3741
                        // Add terms also to content to make terms findable by probabilistic search
3742
                        $file_content = $all_specific_terms.' '.$file_content;
3743
3744
                        if (!$simulation) {
3745
                            $ic_slide->addValue('content', $file_content);
3746
                            $di->addChunk($ic_slide);
3747
                            // Index and return a new search engine document id
3748
                            $did = $di->index();
3749
3750
                            if ($did) {
3751
                                // update the search_did on db
3752
                                $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3753
                                $sql = 'UPDATE %s SET search_did=%d WHERE id=%d LIMIT 1';
3754
                                $sql = sprintf($sql, $tbl_se_ref, (int) $did, (int) $se_ref['id']);
3755
                                Database::query($sql);
3756
                            }
3757
                        }
3758
                    }
3759
                } else {
3760
                    // Add all terms
3761
                    $all_specific_terms = '';
3762
                    foreach ($specific_fields as $specific_field) {
3763
                        if (isset($specific_fields_values[$specific_field['code']])) {
3764
                            $sterms = trim($specific_fields_values[$specific_field['code']]);
3765
                        } else { //if the specific field is not defined, force an empty one
3766
                            $sterms = '';
3767
                        }
3768
                        $all_specific_terms .= ' '.$sterms;
3769
                        if (!empty($sterms)) {
3770
                            $sterms = explode(',', $sterms);
3771
                            foreach ($sterms as $sterm) {
3772
                                if (!$simulation) {
3773
                                    $ic_slide->addTerm(trim($sterm), $specific_field['code']);
3774
                                    add_specific_field_value(
3775
                                        $specific_field['id'],
3776
                                        $course_code,
3777
                                        TOOL_DOCUMENT,
3778
                                        $docid,
3779
                                        $sterm
3780
                                    );
3781
                                }
3782
                            }
3783
                        }
3784
                    }
3785
                    // Add terms also to content to make terms findable by probabilistic search
3786
                    $file_content = $all_specific_terms.' '.$file_content;
3787
                    if (!$simulation) {
3788
                        $ic_slide->addValue('content', $file_content);
3789
                        $di->addChunk($ic_slide);
3790
                        // Index and return search engine document id
3791
                        $did = $di->index();
3792
                        if ($did) {
3793
                            // Save it to db
3794
                            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3795
                            $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
3796
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
3797
                            $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid, $did);
3798
                            Database::query($sql);
3799
                        } else {
3800
                            return false;
3801
                        }
3802
                    }
3803
                }
3804
            } else {
3805
                return false;
3806
            }
3807
        }
3808
3809
        return true;
3810
    }
3811
3812
    /**
3813
     * @return array
3814
     */
3815
    public static function get_web_odf_extension_list()
3816
    {
3817
        return ['ods', 'odt', 'odp'];
3818
    }
3819
3820
    /**
3821
     * Set of extension allowed to use Jodconverter.
3822
     *
3823
     * @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...
3824
     *              'to'
3825
     *              'all'
3826
     * @param $format   'text'
3827
     *                  'spreadsheet'
3828
     *                  'presentation'
3829
     *                  'drawing'
3830
     *                  'all'
3831
     *
3832
     * @return array
3833
     */
3834
    public static function getJodconverterExtensionList($mode, $format)
3835
    {
3836
        $extensionList = [];
3837
        $extensionListFromText = [
3838
            'odt',
3839
            'sxw',
3840
            'rtf',
3841
            'doc',
3842
            'docx',
3843
            'wpd',
3844
            'txt',
3845
        ];
3846
        $extensionListToText = [
3847
            'pdf',
3848
            'odt',
3849
            'sxw',
3850
            'rtf',
3851
            'doc',
3852
            'docx',
3853
            'txt',
3854
        ];
3855
        $extensionListFromSpreadsheet = [
3856
            'ods',
3857
            'sxc',
3858
            'xls',
3859
            'xlsx',
3860
            'csv',
3861
            'tsv',
3862
        ];
3863
        $extensionListToSpreadsheet = [
3864
            'pdf',
3865
            'ods',
3866
            'sxc',
3867
            'xls',
3868
            'xlsx',
3869
            'csv',
3870
            'tsv',
3871
        ];
3872
        $extensionListFromPresentation = [
3873
            'odp',
3874
            'sxi',
3875
            'ppt',
3876
            'pptx',
3877
        ];
3878
        $extensionListToPresentation = [
3879
            'pdf',
3880
            'swf',
3881
            'odp',
3882
            'sxi',
3883
            'ppt',
3884
            'pptx',
3885
        ];
3886
        $extensionListFromDrawing = ['odg'];
3887
        $extensionListToDrawing = ['svg', 'swf'];
3888
3889
        if ($mode === 'from') {
3890
            if ($format === 'text') {
3891
                $extensionList = array_merge($extensionList, $extensionListFromText);
3892
            } elseif ($format === 'spreadsheet') {
3893
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3894
            } elseif ($format === 'presentation') {
3895
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3896
            } elseif ($format === 'drawing') {
3897
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3898
            } elseif ($format === 'all') {
3899
                $extensionList = array_merge($extensionList, $extensionListFromText);
3900
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3901
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3902
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3903
            }
3904
        } elseif ($mode === 'to') {
3905
            if ($format === 'text') {
3906
                $extensionList = array_merge($extensionList, $extensionListToText);
3907
            } elseif ($format === 'spreadsheet') {
3908
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3909
            } elseif ($format === 'presentation') {
3910
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3911
            } elseif ($format === 'drawing') {
3912
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3913
            } elseif ($format === 'all') {
3914
                $extensionList = array_merge($extensionList, $extensionListToText);
3915
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3916
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3917
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3918
            }
3919
        } elseif ($mode === 'all') {
3920
            if ($format === 'text') {
3921
                $extensionList = array_merge($extensionList, $extensionListFromText);
3922
                $extensionList = array_merge($extensionList, $extensionListToText);
3923
            } elseif ($format === 'spreadsheet') {
3924
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3925
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3926
            } elseif ($format === 'presentation') {
3927
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3928
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3929
            } elseif ($format === 'drawing') {
3930
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3931
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3932
            } elseif ($format === 'all') {
3933
                $extensionList = array_merge($extensionList, $extensionListFromText);
3934
                $extensionList = array_merge($extensionList, $extensionListToText);
3935
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3936
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3937
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3938
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3939
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3940
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3941
            }
3942
        }
3943
3944
        return $extensionList;
3945
    }
3946
3947
    /**
3948
     * Get Format type list by extension and mode.
3949
     *
3950
     * @param string $mode Mode to search format type list
3951
     *
3952
     * @example 'from'
3953
     * @example 'to'
3954
     *
3955
     * @param string $extension file extension to check file type
3956
     *
3957
     * @return array
3958
     */
3959
    public static function getFormatTypeListConvertor($mode = 'from', $extension)
3960
    {
3961
        $formatTypesList = [];
3962
        $formatTypes = ['text', 'spreadsheet', 'presentation', 'drawing'];
3963
        foreach ($formatTypes as $formatType) {
3964
            if (in_array($extension, self::getJodconverterExtensionList($mode, $formatType))) {
3965
                $formatTypesList[] = $formatType;
3966
            }
3967
        }
3968
3969
        return $formatTypesList;
3970
    }
3971
3972
    /**
3973
     * @param string $path
3974
     * @param bool   $is_certificate_mode
3975
     *
3976
     * @return bool
3977
     */
3978
    public static function is_folder_to_avoid($path, $is_certificate_mode = false)
3979
    {
3980
        $foldersToAvoid = [
3981
            '/HotPotatoes_files',
3982
            '/certificates',
3983
        ];
3984
        $systemFolder = api_get_course_setting('show_system_folders');
3985
3986
        if ($systemFolder == 1) {
3987
            $foldersToAvoid = [];
3988
        }
3989
3990
        if (basename($path) == 'css') {
3991
            return true;
3992
        }
3993
3994
        if ($is_certificate_mode == false) {
3995
            //Certificate results
3996
            if (strstr($path, 'certificates')) {
3997
                return true;
3998
            }
3999
        }
4000
4001
        // Admin setting for Hide/Show the folders of all users
4002
        if (api_get_setting('show_users_folders') == 'false') {
4003
            $foldersToAvoid[] = '/shared_folder';
4004
4005
            if (strstr($path, 'shared_folder_session_')) {
4006
                return true;
4007
            }
4008
        }
4009
4010
        // Admin setting for Hide/Show Default folders to all users
4011
        if (api_get_setting('show_default_folders') == 'false') {
4012
            $foldersToAvoid[] = '/images';
4013
            $foldersToAvoid[] = '/flash';
4014
            $foldersToAvoid[] = '/audio';
4015
            $foldersToAvoid[] = '/video';
4016
        }
4017
4018
        // Admin setting for Hide/Show chat history folder
4019
        if (api_get_setting('show_chat_folder') == 'false') {
4020
            $foldersToAvoid[] = '/chat_files';
4021
        }
4022
4023
        if (is_array($foldersToAvoid)) {
4024
            return in_array($path, $foldersToAvoid);
4025
        } else {
4026
            return false;
4027
        }
4028
    }
4029
4030
    /**
4031
     * @return array
4032
     */
4033
    public static function get_system_folders()
4034
    {
4035
        return [
4036
            '/certificates',
4037
            '/HotPotatoes_files',
4038
            '/chat_files',
4039
            '/images',
4040
            '/flash',
4041
            '/audio',
4042
            '/video',
4043
            '/shared_folder',
4044
            '/learning_path',
4045
        ];
4046
    }
4047
4048
    /**
4049
     * @return array
4050
     */
4051
    public static function getProtectedFolderFromStudent()
4052
    {
4053
        return [
4054
            '/certificates',
4055
            '/HotPotatoes_files',
4056
            '/chat_files',
4057
            '/shared_folder',
4058
            '/learning_path',
4059
        ];
4060
    }
4061
4062
    /**
4063
     * @param string $courseCode
4064
     *
4065
     * @return string 'visible' or 'invisible' string
4066
     */
4067
    public static function getDocumentDefaultVisibility($courseCode)
4068
    {
4069
        $settings = api_get_setting('tool_visible_by_default_at_creation');
4070
        $defaultVisibility = 'visible';
4071
4072
        if (isset($settings['documents'])) {
4073
            $portalDefaultVisibility = 'invisible';
4074
            if ($settings['documents'] == 'true') {
4075
                $portalDefaultVisibility = 'visible';
4076
            }
4077
4078
            $defaultVisibility = $portalDefaultVisibility;
4079
        }
4080
4081
        if (api_get_setting('documents_default_visibility_defined_in_course') == 'true') {
4082
            $courseVisibility = api_get_course_setting('documents_default_visibility', $courseCode);
4083
            if (!empty($courseVisibility) && in_array($courseVisibility, ['visible', 'invisible'])) {
4084
                $defaultVisibility = $courseVisibility;
4085
            }
4086
        }
4087
4088
        return $defaultVisibility;
4089
    }
4090
4091
    /**
4092
     * @param array  $courseInfo
4093
     * @param int    $id         doc id
4094
     * @param string $visibility visible/invisible
4095
     * @param int    $userId
4096
     */
4097
    public static function updateVisibilityFromAllSessions($courseInfo, $id, $visibility, $userId)
4098
    {
4099
        $sessionList = SessionManager::get_session_by_course($courseInfo['real_id']);
4100
4101
        if (!empty($sessionList)) {
4102
            foreach ($sessionList as $session) {
4103
                $sessionId = $session['id'];
4104
                api_item_property_update(
4105
                    $courseInfo,
4106
                    TOOL_DOCUMENT,
4107
                    $id,
4108
                    $visibility,
4109
                    $userId,
4110
                    null,
4111
                    null,
4112
                    null,
4113
                    null,
4114
                    $sessionId
4115
                );
4116
            }
4117
        }
4118
    }
4119
4120
    /**
4121
     * @param string $file
4122
     *
4123
     * @return string
4124
     */
4125
    public static function readNanogongFile($file)
4126
    {
4127
        $nanoGongJarFile = api_get_path(WEB_LIBRARY_PATH).'nanogong/nanogong.jar';
4128
        $html = '<applet id="applet" archive="'.$nanoGongJarFile.'" code="gong.NanoGong" width="160" height="95">';
4129
        $html .= '<param name="SoundFileURL" value="'.$file.'" />';
4130
        $html .= '<param name="ShowSaveButton" value="false" />';
4131
        $html .= '<param name="ShowTime" value="true" />';
4132
        $html .= '<param name="ShowRecordButton" value="false" />';
4133
        $html .= '</applet>';
4134
4135
        return $html;
4136
    }
4137
4138
    /**
4139
     * @param string $filePath
4140
     * @param string $path
4141
     * @param array  $courseInfo
4142
     * @param int    $sessionId
4143
     * @param string $whatIfFileExists overwrite|rename
4144
     * @param int    $userId
4145
     * @param int    $groupId
4146
     * @param int    $toUserId
4147
     * @param string $comment
4148
     *
4149
     * @return bool|path
4150
     */
4151
    public static function addFileToDocumentTool(
4152
        $filePath,
4153
        $path,
4154
        $courseInfo,
4155
        $sessionId,
4156
        $userId,
4157
        $whatIfFileExists = 'overwrite',
4158
        $groupId = null,
4159
        $toUserId = null,
4160
        $comment = null
4161
    ) {
4162
        if (!file_exists($filePath)) {
4163
            return false;
4164
        }
4165
4166
        $fileInfo = pathinfo($filePath);
4167
4168
        $file = [
4169
            'name' => $fileInfo['basename'],
4170
            'tmp_name' => $filePath,
4171
            'size' => filesize($filePath),
4172
            'from_file' => true,
4173
        ];
4174
4175
        $course_dir = $courseInfo['path'].'/document';
4176
        $baseWorkDir = api_get_path(SYS_COURSE_PATH).$course_dir;
4177
4178
        $filePath = handle_uploaded_document(
4179
            $courseInfo,
4180
            $file,
4181
            $baseWorkDir,
4182
            $path,
4183
            $userId,
4184
            $groupId,
4185
            $toUserId,
4186
            false,
4187
            $whatIfFileExists,
4188
            false,
4189
            false,
4190
            $comment,
4191
            $sessionId
4192
        );
4193
4194
        if ($filePath) {
4195
            return self::get_document_id(
4196
                $courseInfo,
4197
                $filePath,
4198
                $sessionId
4199
            );
4200
        }
4201
4202
        return false;
4203
    }
4204
4205
    /**
4206
     * Converts wav to mp3 file.
4207
     * Requires the ffmpeg lib. In ubuntu: sudo apt-get install ffmpeg.
4208
     *
4209
     * @param string $wavFile
4210
     * @param bool   $removeWavFileIfSuccess
4211
     *
4212
     * @return bool
4213
     */
4214
    public static function convertWavToMp3($wavFile, $removeWavFileIfSuccess = false)
4215
    {
4216
        if (file_exists($wavFile)) {
4217
            try {
4218
                $ffmpeg = \FFMpeg\FFMpeg::create();
4219
                $video = $ffmpeg->open($wavFile);
4220
4221
                $mp3File = str_replace('wav', 'mp3', $wavFile);
4222
                $result = $video->save(new FFMpeg\Format\Audio\Mp3(), $mp3File);
4223
                if ($result && $removeWavFileIfSuccess) {
4224
                    unlink($wavFile);
4225
                }
4226
4227
                if (file_exists($mp3File)) {
4228
                    return $mp3File;
4229
                }
4230
            } catch (Exception $e) {
4231
                error_log($e->getMessage());
4232
                error_log($e->getPrevious()->getMessage());
4233
            }
4234
        }
4235
4236
        return false;
4237
    }
4238
4239
    /**
4240
     * @param string $documentData     wav document information
4241
     * @param array  $courseInfo
4242
     * @param int    $sessionId
4243
     * @param int    $userId           user that adds the document
4244
     * @param string $whatIfFileExists
4245
     * @param bool   $deleteWavFile
4246
     *
4247
     * @return bool
4248
     */
4249
    public static function addAndConvertWavToMp3(
4250
        $documentData,
4251
        $courseInfo,
4252
        $sessionId,
4253
        $userId,
4254
        $whatIfFileExists = 'overwrite',
4255
        $deleteWavFile = false
4256
    ) {
4257
        if (empty($documentData)) {
4258
            return false;
4259
        }
4260
4261
        if (isset($documentData['absolute_path']) &&
4262
            file_exists($documentData['absolute_path'])
4263
        ) {
4264
            $mp3FilePath = self::convertWavToMp3($documentData['absolute_path']);
4265
            error_log($mp3FilePath);
4266
4267
            if (!empty($mp3FilePath) && file_exists($mp3FilePath)) {
4268
                $documentId = self::addFileToDocumentTool(
4269
                    $mp3FilePath,
4270
                    dirname($documentData['path']),
4271
                    $courseInfo,
4272
                    $sessionId,
4273
                    $userId,
4274
                    $whatIfFileExists,
4275
                    null,
4276
                    null,
4277
                    $documentData['comment']
4278
                );
4279
4280
                if (!empty($documentId)) {
4281
                    if ($deleteWavFile) {
4282
                        $coursePath = $courseInfo['directory'].'/document';
4283
                        $documentPath = api_get_path(SYS_COURSE_PATH).$coursePath;
4284
                        self::delete_document(
4285
                            $courseInfo,
4286
                            null,
4287
                            $documentPath,
4288
                            $sessionId,
4289
                            $documentData['id']
4290
                        );
4291
                    }
4292
4293
                    return $documentId;
4294
                }
4295
            }
4296
        }
4297
4298
        return false;
4299
    }
4300
4301
    /**
4302
     * Sets.
4303
     *
4304
     * @param string $file         ($document_data['path'])
4305
     * @param string $file_url_sys
4306
     *
4307
     * @return string
4308
     */
4309
    public static function generateAudioTempFile($file, $file_url_sys)
4310
    {
4311
        //make temp audio
4312
        $temp_folder = api_get_path(SYS_ARCHIVE_PATH).'temp/audio';
4313
        if (!file_exists($temp_folder)) {
4314
            @mkdir($temp_folder, api_get_permissions_for_new_directories(), true);
4315
        }
4316
4317
        //make htaccess with allow from all, and file index.html into temp/audio
4318
        $htaccess = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess';
4319
        if (!file_exists($htaccess)) {
4320
            $htaccess_content = "order deny,allow\r\nallow from all\r\nOptions -Indexes";
4321
            $fp = @fopen(api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess', 'w');
4322
            if ($fp) {
4323
                fwrite($fp, $htaccess_content);
4324
                fclose($fp);
4325
            }
4326
        }
4327
4328
        //encript temp name file
4329
        $name_crip = sha1(uniqid()); //encript
4330
        $findext = explode(".", $file);
4331
        $extension = $findext[count($findext) - 1];
4332
        $file_crip = $name_crip.'.'.$extension;
4333
4334
        //copy file to temp/audio directory
4335
        $from_sys = $file_url_sys;
4336
        $to_sys = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/'.$file_crip;
4337
4338
        if (file_exists($from_sys)) {
4339
            copy($from_sys, $to_sys);
4340
        }
4341
4342
        // get file from tmp directory
4343
        Session::write('temp_audio_nanogong', $to_sys);
4344
4345
        return api_get_path(WEB_ARCHIVE_PATH).'temp/audio/'.$file_crip;
4346
    }
4347
4348
    /**
4349
     * Erase temp nanogong audio.
4350
     */
4351
    public static function removeGeneratedAudioTempFile()
4352
    {
4353
        $tempAudio = Session::read('temp_audio_nanogong');
4354
        if (!empty(isset($tempAudio)) && is_file($tempAudio)) {
4355
            unlink($tempAudio);
4356
            Session::erase('temp_audio_nanogong');
4357
        }
4358
    }
4359
4360
    /**
4361
     * Check if the past is used in this course.
4362
     *
4363
     * @param array  $courseInfo
4364
     * @param string $path
4365
     *
4366
     * @return array
4367
     */
4368
    public static function getDocumentByPathInCourse($courseInfo, $path)
4369
    {
4370
        $table = Database::get_course_table(TABLE_DOCUMENT);
4371
        $path = Database::escape_string($path);
4372
        $courseId = $courseInfo['real_id'];
4373
        if (empty($courseId)) {
4374
            return false;
4375
        }
4376
        $sql = "SELECT * FROM $table WHERE c_id = $courseId AND path = '$path'";
4377
        $result = Database::query($sql);
4378
4379
        return Database::store_result($result, 'ASSOC');
4380
    }
4381
4382
    /**
4383
     * @param array $_course
4384
     *
4385
     * @return int
4386
     */
4387
    public static function createDefaultAudioFolder($_course)
4388
    {
4389
        if (!isset($_course['path'])) {
4390
            return false;
4391
        }
4392
4393
        $audioId = null;
4394
        $path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document/';
4395
        if (!is_dir($path.'audio')) {
4396
            mkdir($path.'audio', api_get_permissions_for_new_directories());
4397
            $audioId = add_document($_course, '/audio', 'folder', 0, 'Audio');
4398
            api_item_property_update(
4399
                $_course,
4400
                TOOL_DOCUMENT,
4401
                $audioId,
4402
                'FolderCreated',
4403
                api_get_user_id(),
4404
                null,
4405
                null,
4406
                null,
4407
                null,
4408
                api_get_session_id()
4409
            );
4410
        }
4411
4412
        return $audioId;
4413
    }
4414
4415
    /**
4416
     * Generate a default certificate for a courses.
4417
     *
4418
     * @todo move to certificate lib
4419
     *
4420
     * @global string $css CSS directory
4421
     * @global string $img_dir image directory
4422
     * @global string $default_course_dir Course directory
4423
     * @global string $js JS directory
4424
     *
4425
     * @param array $courseData     The course info
4426
     * @param bool  $fromBaseCourse
4427
     * @param int   $sessionId
4428
     */
4429
    public static function generateDefaultCertificate(
4430
        $courseData,
4431
        $fromBaseCourse = false,
4432
        $sessionId = 0
4433
    ) {
4434
        if (empty($courseData)) {
4435
            return false;
4436
        }
4437
4438
        global $css, $img_dir, $default_course_dir, $js;
4439
        $codePath = api_get_path(REL_CODE_PATH);
4440
        $dir = '/certificates';
4441
        $comment = null;
4442
        $title = get_lang('DefaultCertificate');
4443
        $fileName = api_replace_dangerous_char($title);
4444
        $filePath = api_get_path(SYS_COURSE_PATH)."{$courseData['directory']}/document$dir";
4445
4446
        if (!is_dir($filePath)) {
4447
            mkdir($filePath, api_get_permissions_for_new_directories());
4448
        }
4449
4450
        $fileFullPath = "$filePath/$fileName.html";
4451
        $fileType = 'file';
4452
        $templateContent = file_get_contents(api_get_path(SYS_CODE_PATH).'gradebook/certificate_template/template.html');
4453
4454
        $search = ['{CSS}', '{IMG_DIR}', '{REL_CODE_PATH}', '{COURSE_DIR}'];
4455
        $replace = [$css.$js, $img_dir, $codePath, $default_course_dir];
4456
4457
        $fileContent = str_replace($search, $replace, $templateContent);
4458
        $saveFilePath = "$dir/$fileName.html";
4459
4460
        if ($fromBaseCourse) {
4461
            $defaultCertificateId = self::get_default_certificate_id(
4462
                $courseData['code'],
4463
                0
4464
            );
4465
            if (!empty($defaultCertificateId)) {
4466
                // We have a certificate from the course base
4467
                $documentData = self::get_document_data_by_id(
4468
                    $defaultCertificateId,
4469
                    $courseData['code'],
4470
                    false,
4471
                    0
4472
                );
4473
4474
                if ($documentData) {
4475
                    $fileContent = file_get_contents($documentData['absolute_path']);
4476
                }
4477
            }
4478
        }
4479
4480
        if (file_exists($fileFullPath) === false) {
4481
            $result = file_put_contents($fileFullPath, $fileContent);
4482
            if ($result) {
4483
                $fileSize = filesize($fileFullPath);
4484
4485
                $documentId = add_document(
4486
                    $courseData,
4487
                    $saveFilePath,
4488
                    $fileType,
4489
                    $fileSize,
4490
                    $title,
4491
                    $comment,
4492
                    0, //$readonly = 0,
4493
                    true, //$save_visibility = true,
4494
                    null, //$group_id = null,
4495
                    $sessionId
4496
                );
4497
4498
                api_item_property_update(
4499
                    $courseData,
4500
                    TOOL_DOCUMENT,
4501
                    $documentId,
4502
                    'DocumentAdded',
4503
                    api_get_user_id(),
4504
                    null,
4505
                    null,
4506
                    null,
4507
                    null,
4508
                    $sessionId
4509
                );
4510
4511
                $defaultCertificateId = self::get_default_certificate_id(
4512
                    $courseData['code'],
4513
                    $sessionId
4514
                );
4515
4516
                if (!isset($defaultCertificateId)) {
4517
                    self::attach_gradebook_certificate(
4518
                        $courseData['code'],
4519
                        $documentId,
4520
                        $sessionId
4521
                    );
4522
                }
4523
            }
4524
        }
4525
    }
4526
4527
    /**
4528
     * Update the document name.
4529
     *
4530
     * @param int    $documentId The document id
4531
     * @param string $newName    The new name
4532
     */
4533
    public static function renameDocument($documentId, $newName)
4534
    {
4535
        $documentId = intval($documentId);
4536
        $newName = Database::escape_string($newName);
4537
        $docuentTable = Database::get_course_table(TABLE_DOCUMENT);
4538
4539
        $values = [
4540
            'title' => $newName,
4541
        ];
4542
4543
        $whereConditions = [
4544
            'id = ?' => $documentId,
4545
        ];
4546
4547
        Database::update($docuentTable, $values, $whereConditions);
4548
    }
4549
4550
    /**
4551
     * Get folder/file suffix.
4552
     *
4553
     * @param array $courseInfo
4554
     * @param int   $sessionId
4555
     * @param int   $groupId
4556
     *
4557
     * @return string
4558
     */
4559
    public static function getDocumentSuffix($courseInfo, $sessionId, $groupId)
4560
    {
4561
        // If no session or group, then no suffix.
4562
        if (empty($sessionId) && empty($groupId)) {
4563
            return '';
4564
        }
4565
4566
        return '__'.intval($sessionId).'__'.intval($groupId);
4567
    }
4568
4569
    /**
4570
     * Fix a document name adding session id and group id
4571
     * Turns picture.jpg -> picture__1__2.jpg
4572
     * Where 1 = session id and 2 group id
4573
     * Of session id and group id are empty then the function returns:
4574
     * picture.jpg ->  picture.jpg.
4575
     *
4576
     * @param string $name       folder or file name
4577
     * @param string $type       'folder' or 'file'
4578
     * @param array  $courseInfo
4579
     * @param int    $sessionId
4580
     * @param int    $groupId
4581
     *
4582
     * @return string
4583
     */
4584
    public static function fixDocumentName($name, $type, $courseInfo, $sessionId, $groupId)
4585
    {
4586
        $suffix = self::getDocumentSuffix($courseInfo, $sessionId, $groupId);
4587
4588
        switch ($type) {
4589
            case 'folder':
4590
                $name = $name.$suffix;
4591
                break;
4592
            case 'file':
4593
                $name = self::addSuffixToFileName($name, $suffix);
4594
                break;
4595
        }
4596
4597
        return $name;
4598
    }
4599
4600
    /**
4601
     * Add a suffix to a file Example:
4602
     * /folder/picture.jpg => to /folder/picture_this.jpg
4603
     * where "_this" is the suffix.
4604
     *
4605
     * @param string $name
4606
     * @param string $suffix
4607
     *
4608
     * @return string
4609
     */
4610
    public static function addSuffixToFileName($name, $suffix)
4611
    {
4612
        $extension = pathinfo($name, PATHINFO_EXTENSION);
4613
        $fileName = pathinfo($name, PATHINFO_FILENAME);
4614
        $dir = pathinfo($name, PATHINFO_DIRNAME);
4615
4616
        if ($dir == '.') {
4617
            $dir = null;
4618
        }
4619
4620
        if (!empty($dir) && $dir != '/') {
4621
            $dir = $dir.'/';
4622
        }
4623
4624
        $name = $dir.$fileName.$suffix.'.'.$extension;
4625
4626
        return $name;
4627
    }
4628
4629
    /**
4630
     * Check if folder exist in the course base or in the session course.
4631
     *
4632
     * @param string $folder     Example: /folder/folder2
4633
     * @param array  $courseInfo
4634
     * @param int    $sessionId
4635
     * @param int    $groupId    group.id
4636
     *
4637
     * @return bool
4638
     */
4639
    public static function folderExists(
4640
        $folder,
4641
        $courseInfo,
4642
        $sessionId,
4643
        $groupId
4644
    ) {
4645
        $courseId = $courseInfo['real_id'];
4646
4647
        if (empty($courseId)) {
4648
            return false;
4649
        }
4650
4651
        $sessionId = intval($sessionId);
4652
        $folderWithSuffix = self::fixDocumentName(
4653
            $folder,
4654
            'folder',
4655
            $courseInfo,
4656
            $sessionId,
4657
            $groupId
4658
        );
4659
4660
        $folder = Database::escape_string($folder);
4661
        $folderWithSuffix = Database::escape_string($folderWithSuffix);
4662
4663
        // Check if pathname already exists inside document table
4664
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
4665
        $sql = "SELECT id, path FROM $tbl_document
4666
                WHERE
4667
                    filetype = 'folder' AND
4668
                    c_id = $courseId AND
4669
                    (path = '$folder' OR path = '$folderWithSuffix') AND
4670
                    (session_id = 0 OR session_id = $sessionId)
4671
        ";
4672
4673
        $rs = Database::query($sql);
4674
        if (Database::num_rows($rs)) {
4675
            return true;
4676
        }
4677
4678
        return false;
4679
    }
4680
4681
    /**
4682
     * Check if file exist in the course base or in the session course.
4683
     *
4684
     * @param string $fileName   Example: /folder/picture.jpg
4685
     * @param array  $courseInfo
4686
     * @param int    $sessionId
4687
     * @param int    $groupId
4688
     *
4689
     * @return bool
4690
     */
4691
    public static function documentExists(
4692
        $fileName,
4693
        $courseInfo,
4694
        $sessionId,
4695
        $groupId
4696
    ) {
4697
        $courseId = $courseInfo['real_id'];
4698
4699
        if (empty($courseId)) {
4700
            return false;
4701
        }
4702
4703
        $sessionId = intval($sessionId);
4704
        $fileNameEscape = Database::escape_string($fileName);
4705
4706
        $fileNameWithSuffix = self::fixDocumentName(
4707
            $fileName,
4708
            'file',
4709
            $courseInfo,
4710
            $sessionId,
4711
            $groupId
4712
        );
4713
4714
        $fileNameWithSuffix = Database::escape_string($fileNameWithSuffix);
4715
4716
        // Check if pathname already exists inside document table
4717
        $table = Database::get_course_table(TABLE_DOCUMENT);
4718
        $sql = "SELECT id, path FROM $table
4719
                WHERE
4720
                    filetype = 'file' AND
4721
                    c_id = $courseId AND
4722
                    (
4723
                        path = '".$fileNameEscape."' OR
4724
                        path = '$fileNameWithSuffix'
4725
                    ) AND
4726
                    (session_id = 0 OR session_id = $sessionId)
4727
        ";
4728
        $rs = Database::query($sql);
4729
        if (Database::num_rows($rs)) {
4730
            return true;
4731
        }
4732
4733
        return false;
4734
    }
4735
4736
    /**
4737
     * Undo the suffix applied to a file example:
4738
     * turns picture__1__1.jpg to picture.jpg.
4739
     *
4740
     * @param string $name
4741
     * @param int    $courseId
4742
     * @param int    $sessionId
4743
     * @param int    $groupId
4744
     *
4745
     * @return string
4746
     */
4747
    public static function undoFixDocumentName(
4748
        $name,
4749
        $courseId,
4750
        $sessionId,
4751
        $groupId
4752
    ) {
4753
        if (empty($sessionId) && empty($groupId)) {
4754
            return $name;
4755
        }
4756
4757
        $suffix = self::getDocumentSuffix(
4758
            ['real_id' => $courseId],
4759
            $sessionId,
4760
            $groupId
4761
        );
4762
4763
        $name = str_replace($suffix, '', $name);
4764
4765
        return $name;
4766
    }
4767
4768
    /**
4769
     * @param string $path
4770
     * @param string $name
4771
     * @param array  $courseInfo
4772
     * @param int    $sessionId
4773
     * @param int    $groupId
4774
     *
4775
     * @return string
4776
     */
4777
    public static function getUniqueFileName($path, $name, $courseInfo, $sessionId, $groupId)
4778
    {
4779
        $counter = 1;
4780
        $filePath = $path.$name;
4781
        $uniqueName = $name;
4782
        while ($documentExists = self::documentExists(
4783
            $filePath,
4784
            $courseInfo,
4785
            $sessionId,
4786
            $groupId
4787
        )) {
4788
            $uniqueName = self::addSuffixToFileName($name, '_'.$counter);
4789
            $filePath = $path.$uniqueName;
4790
            $counter++;
4791
        }
4792
4793
        return $uniqueName;
4794
    }
4795
4796
    /**
4797
     * Builds the form that enables the user to
4798
     * select a directory to browse/upload in.
4799
     *
4800
     * @param array    An array containing the folders we want to be able to select
4801
     * @param string    The current folder (path inside of the "document" directory, including the prefix "/")
4802
     * @param string    Group directory, if empty, prevents documents to be uploaded
4803
     * (because group documents cannot be uploaded in root)
4804
     * @param bool    Whether to change the renderer (this will add a template <span>
4805
     * to the QuickForm object displaying the form)
4806
     *
4807
     * @return string html form
4808
     */
4809
    public static function build_directory_selector(
4810
        $folders,
4811
        $document_id,
4812
        $group_dir = '',
4813
        $change_renderer = false,
4814
        &$form = null,
4815
        $selectName = 'id'
4816
    ) {
4817
        $doc_table = Database::get_course_table(TABLE_DOCUMENT);
4818
        $course_id = api_get_course_int_id();
4819
        $folder_titles = [];
4820
4821
        if (is_array($folders)) {
4822
            $escaped_folders = [];
4823
            foreach ($folders as $key => &$val) {
4824
                $escaped_folders[$key] = Database::escape_string($val);
4825
            }
4826
            $folder_sql = implode("','", $escaped_folders);
4827
4828
            $sql = "SELECT path, title 
4829
                    FROM $doc_table
4830
                    WHERE 
4831
                        filetype = 'folder' AND 
4832
                        c_id = $course_id AND 
4833
                        path IN ('".$folder_sql."')";
4834
            $res = Database::query($sql);
4835
            $folder_titles = [];
4836
            while ($obj = Database::fetch_object($res)) {
4837
                $folder_titles[$obj->path] = $obj->title;
4838
            }
4839
        }
4840
4841
        $attributes = [];
4842
        if (empty($form)) {
4843
            $form = new FormValidator('selector', 'GET', api_get_self().'?'.api_get_cidreq());
4844
            $attributes = ['onchange' => 'javascript: document.selector.submit();'];
4845
        }
4846
        $form->addElement('hidden', 'cidReq', api_get_course_id());
4847
        $parent_select = $form->addSelect(
4848
            $selectName,
4849
            get_lang('CurrentDirectory'),
4850
            '',
4851
            $attributes
4852
        );
4853
4854
        // Group documents cannot be uploaded in the root
4855
        if (empty($group_dir)) {
4856
            $parent_select->addOption(get_lang('Documents'), '/');
4857
4858
            if (is_array($folders)) {
4859
                foreach ($folders as $folder_id => &$folder) {
4860
                    $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
4861
                    $path_parts = explode('/', $folder);
4862
                    $folder_titles[$folder] = cut($folder_titles[$folder], 80);
4863
                    $counter = count($path_parts) - 2;
4864
                    if ($counter > 0) {
4865
                        $label = str_repeat('&nbsp;&nbsp;&nbsp;', $counter).' &mdash; '.$folder_titles[$folder];
4866
                    } else {
4867
                        $label = ' &mdash; '.$folder_titles[$folder];
4868
                    }
4869
                    $parent_select->addOption($label, $folder_id);
4870
                    if ($selected != '') {
4871
                        $parent_select->setSelected($folder_id);
4872
                    }
4873
                }
4874
            }
4875
        } else {
4876
            if (!empty($folders)) {
4877
                foreach ($folders as $folder_id => &$folder) {
4878
                    $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
4879
                    $label = $folder_titles[$folder];
4880
                    if ($folder == $group_dir) {
4881
                        $label = get_lang('Documents');
4882
                    } else {
4883
                        $path_parts = explode('/', str_replace($group_dir, '', $folder));
4884
                        $label = cut($label, 80);
4885
                        $label = str_repeat('&nbsp;&nbsp;&nbsp;', count($path_parts) - 2).' &mdash; '.$label;
4886
                    }
4887
                    $parent_select->addOption($label, $folder_id);
4888
                    if ($selected != '') {
4889
                        $parent_select->setSelected($folder_id);
4890
                    }
4891
                }
4892
            }
4893
        }
4894
4895
        $html = $form->toHtml();
4896
4897
        return $html;
4898
    }
4899
4900
    /**
4901
     * Create a html hyperlink depending on if it's a folder or a file.
4902
     *
4903
     * @param string $documentWebPath
4904
     * @param array  $document_data
4905
     * @param bool   $show_as_icon      - if it is true, only a clickable icon will be shown
4906
     * @param int    $visibility        (1/0)
4907
     * @param int    $counter
4908
     * @param int    $size
4909
     * @param bool   $isAllowedToEdit
4910
     * @param bool   $isCertificateMode
4911
     *
4912
     * @return string url
4913
     */
4914
    public static function create_document_link(
4915
        $documentWebPath,
4916
        $document_data,
4917
        $show_as_icon = false,
4918
        $counter = null,
4919
        $visibility,
4920
        $size = 0,
4921
        $isAllowedToEdit = false,
4922
        $isCertificateMode = false
4923
    ) {
4924
        global $dbl_click_id;
4925
        $www = $documentWebPath;
4926
4927
        $sessionId = api_get_session_id();
4928
        $courseParams = api_get_cidreq();
4929
        $webODFList = self::get_web_odf_extension_list();
4930
4931
        // Get the title or the basename depending on what we're using
4932
        if ($document_data['title'] != '') {
4933
            $title = $document_data['title'];
4934
        } else {
4935
            $title = basename($document_data['path']);
4936
        }
4937
4938
        $filetype = $document_data['filetype'];
4939
        $path = $document_data['path'];
4940
        $url_path = urlencode($document_data['path']);
4941
4942
        // Add class="invisible" on invisible files
4943
        $visibility_class = $visibility == false ? ' class="muted"' : '';
4944
        $forcedownload_link = '';
4945
        $forcedownload_icon = '';
4946
        $prevent_multiple_click = '';
4947
        $force_download_html = '';
4948
4949
        if (!$show_as_icon) {
4950
            // Build download link (icon)
4951
            $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'];
4952
            // Folder download or file download?
4953
            $forcedownload_icon = $filetype == 'folder' ? 'save_pack.png' : 'save.png';
4954
            // Prevent multiple clicks on zipped folder download
4955
            $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; }\"" : '';
4956
        }
4957
4958
        $target = '_self';
4959
        $is_browser_viewable_file = false;
4960
4961
        if ($filetype == 'file') {
4962
            // Check the extension
4963
            $ext = explode('.', $path);
4964
            $ext = strtolower($ext[sizeof($ext) - 1]);
4965
4966
            // HTML-files an some other types are shown in a frameset by default.
4967
            $is_browser_viewable_file = self::isBrowserViewable($ext);
4968
            if ($is_browser_viewable_file) {
4969
                if ($ext == 'pdf' || in_array($ext, $webODFList)) {
4970
                    $url = api_get_self().'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
4971
                } else {
4972
                    $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
4973
                }
4974
            } else {
4975
                // url-encode for problematic characters (we may not call them dangerous characters...)
4976
                //$path = str_replace('%2F', '/', $url_path).'?'.$courseParams;
4977
                $url = $www.str_replace('%2F', '/', $url_path).'?'.$courseParams;
4978
            }
4979
        } else {
4980
            $url = api_get_self().'?'.$courseParams.'&id='.$document_data['id'];
4981
        }
4982
4983
        if ($isCertificateMode) {
4984
            $url .= '&certificate=true&selectcat='.(isset($_GET['selectcat']) ? $_GET['selectcat'] : '');
4985
        }
4986
4987
        // The little download icon
4988
        $tooltip_title = $title;
4989
        $tooltip_title_alt = $tooltip_title;
4990
4991
        if ($filetype == 'link') {
4992
            $tooltip_title_alt = $title;
4993
            $url = $document_data['comment'].'" target="_blank';
4994
        }
4995
4996
        if ($path == '/shared_folder') {
4997
            $tooltip_title_alt = get_lang('UserFolders');
4998
        } elseif (strstr($path, 'shared_folder_session_')) {
4999
            $tooltip_title_alt = get_lang('UserFolders').' ('.api_get_session_name(api_get_session_id()).')';
5000
        } elseif (strstr($tooltip_title, 'sf_user_')) {
5001
            $userinfo = api_get_user_info(substr($tooltip_title, 8));
5002
            $tooltip_title_alt = get_lang('UserFolder').' '.$userinfo['complete_name'];
5003
        } elseif ($path == '/chat_files') {
5004
            $tooltip_title_alt = get_lang('ChatFiles');
5005
        } elseif ($path == '/learning_path') {
5006
            $tooltip_title_alt = get_lang('LearningPaths');
5007
        } elseif ($path == '/video') {
5008
            $tooltip_title_alt = get_lang('Video');
5009
        } elseif ($path == '/audio') {
5010
            $tooltip_title_alt = get_lang('Audio');
5011
        } elseif ($path == '/flash') {
5012
            $tooltip_title_alt = get_lang('Flash');
5013
        } elseif ($path == '/images') {
5014
            $tooltip_title_alt = get_lang('Images');
5015
        } elseif ($path == '/images/gallery') {
5016
            $tooltip_title_alt = get_lang('DefaultCourseImages');
5017
        }
5018
5019
        $copyToMyFiles = $open_in_new_window_link = '';
5020
        $curdirpath = isset($_GET['curdirpath']) ? Security::remove_XSS($_GET['curdirpath']) : null;
5021
        $send_to = null;
5022
        $checkExtension = $path;
5023
        $extension = pathinfo($path, PATHINFO_EXTENSION);
5024
        $document_data['file_extension'] = $extension;
5025
5026
        if (!$show_as_icon) {
5027
            if ($filetype == 'folder') {
5028
                if ($isAllowedToEdit ||
5029
                    api_is_platform_admin() ||
5030
                    api_get_setting('students_download_folders') == 'true'
5031
                ) {
5032
                    // filter: when I am into a shared folder, I can only show "my shared folder" for donwload
5033
                    if (self::is_shared_folder($curdirpath, $sessionId)) {
5034
                        if (preg_match('/shared_folder\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
5035
                            preg_match('/shared_folder_session_'.$sessionId.'\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
5036
                            $isAllowedToEdit || api_is_platform_admin()
5037
                        ) {
5038
                            $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5039
                                Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5040
                        }
5041
                    } elseif (!preg_match('/shared_folder/', urldecode($forcedownload_link)) ||
5042
                        $isAllowedToEdit ||
5043
                        api_is_platform_admin()
5044
                    ) {
5045
                        $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5046
                            Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5047
                    }
5048
                }
5049
            } else {
5050
                $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.' download="'.$document_data['basename'].'">'.
5051
                    Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5052
            }
5053
5054
            // Copy files to user's myfiles
5055
            if (api_get_setting('allow_my_files') === 'true' &&
5056
                api_get_setting('users_copy_files') === 'true' && api_is_anonymous() === false
5057
            ) {
5058
                $copy_myfiles_link = $filetype == 'file' ? api_get_self().'?'.$courseParams.'&action=copytomyfiles&id='.$document_data['id'] : api_get_self().'?'.$courseParams;
5059
                if ($filetype == 'file') {
5060
                    $copyToMyFiles = '<a href="'.$copy_myfiles_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5061
                        Display::return_icon('briefcase.png', get_lang('CopyToMyFiles'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
5062
5063
                    if (api_get_setting('allow_my_files') === 'false') {
5064
                        $copyToMyFiles = '';
5065
                    }
5066
                }
5067
            }
5068
5069
            $pdf_icon = '';
5070
            if (!$isAllowedToEdit &&
5071
                api_get_setting('students_export2pdf') == 'true' &&
5072
                $filetype == 'file' &&
5073
                in_array($extension, ['html', 'htm'])
5074
            ) {
5075
                $pdf_icon = ' <a style="float:right".'.$prevent_multiple_click.' href="'.api_get_self().'?'.$courseParams.'&action=export_to_pdf&id='.$document_data['id'].'&curdirpath='.$curdirpath.'">'.
5076
                    Display::return_icon('pdf.png', get_lang('Export2PDF'), [], ICON_SIZE_SMALL).'</a> ';
5077
            }
5078
5079
            if ($is_browser_viewable_file) {
5080
                $open_in_new_window_link = '<a href="'.$www.str_replace('%2F', '/', $url_path).'?'.$courseParams.'" style="float:right"'.$prevent_multiple_click.' target="_blank">'.
5081
                    Display::return_icon('open_in_new_window.png', get_lang('OpenInANewWindow'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
5082
            }
5083
5084
            if ($filetype == 'file') {
5085
                // Sound preview
5086
                if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5087
                    (preg_match('/wav$/i', urldecode($checkExtension))) ||
5088
                    preg_match('/ogg$/i', urldecode($checkExtension))
5089
                ) {
5090
                    return '<span style="float:left" '.$visibility_class.'>'.
5091
                    $title.
5092
                    '</span>'.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5093
                } elseif (
5094
                    // Show preview
5095
                    preg_match('/swf$/i', urldecode($checkExtension)) ||
5096
                    preg_match('/png$/i', urldecode($checkExtension)) ||
5097
                    preg_match('/gif$/i', urldecode($checkExtension)) ||
5098
                    preg_match('/jpg$/i', urldecode($checkExtension)) ||
5099
                    preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5100
                    preg_match('/bmp$/i', urldecode($checkExtension)) ||
5101
                    preg_match('/svg$/i', urldecode($checkExtension))
5102
                ) {
5103
                    // Simpler version of showinframesmin.php with no headers
5104
                    $url = 'show_content.php?'.$courseParams.'&id='.$document_data['id'];
5105
                    $class = 'ajax';
5106
                    if ($visibility == false) {
5107
                        $class = "ajax text-muted";
5108
                    }
5109
5110
                    return Display::url(
5111
                        $title,
5112
                        $url,
5113
                        [
5114
                            'class' => $class,
5115
                            'title' => $tooltip_title_alt,
5116
                            'data-title' => $title,
5117
                            'style' => 'float:left;',
5118
                        ]
5119
                    )
5120
                    .$force_download_html.$send_to.$copyToMyFiles
5121
                    .$open_in_new_window_link.$pdf_icon;
5122
                } else {
5123
                    // For a "PDF Download" of the file.
5124
                    $pdfPreview = null;
5125
                    if ($ext != 'pdf' && !in_array($ext, $webODFList)) {
5126
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
5127
                    } else {
5128
                        $pdfPreview = Display::url(
5129
                            Display::return_icon('preview.png', get_lang('Preview'), null, ICON_SIZE_SMALL),
5130
                            api_get_path(WEB_CODE_PATH).'document/showinframes.php?'.$courseParams.'&id='.$document_data['id'],
5131
                            ['style' => 'float:right']
5132
                        );
5133
                    }
5134
                    // No plugin just the old and good showinframes.php page
5135
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" style="float:left" '.$visibility_class.' >'.$title.'</a>'.
5136
                    $pdfPreview.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5137
                }
5138
            } else {
5139
                return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.$title.'</a>'.
5140
                $force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5141
            }
5142
            // end copy files to users myfiles
5143
        } else {
5144
            // Icon column
5145
            if (preg_match('/shared_folder/', urldecode($checkExtension)) &&
5146
                preg_match('/shared_folder$/', urldecode($checkExtension)) == false &&
5147
                preg_match('/shared_folder_session_'.$sessionId.'$/', urldecode($url)) == false
5148
            ) {
5149
                if ($filetype == 'file') {
5150
                    //Sound preview
5151
                    if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5152
                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
5153
                        preg_match('/ogg$/i', urldecode($checkExtension))) {
5154
                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
5155
5156
                        return $soundPreview;
5157
                    } elseif (
5158
                        // Show preview
5159
                        preg_match('/swf$/i', urldecode($checkExtension)) ||
5160
                        preg_match('/png$/i', urldecode($checkExtension)) ||
5161
                        preg_match('/gif$/i', urldecode($checkExtension)) ||
5162
                        preg_match('/jpg$/i', urldecode($checkExtension)) ||
5163
                        preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5164
                        preg_match('/bmp$/i', urldecode($checkExtension)) ||
5165
                        preg_match('/svg$/i', urldecode($checkExtension))
5166
                    ) {
5167
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
5168
5169
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5170
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5171
                            Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5172
                        '</a>';
5173
                    } else {
5174
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5175
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5176
                            Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5177
                        '</a>';
5178
                    }
5179
                } else {
5180
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
5181
                        self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5182
                        Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5183
                    '</a>';
5184
                }
5185
            } else {
5186
                if ($filetype == 'file') {
5187
                    // Sound preview with jplayer
5188
                    if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5189
                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
5190
                        preg_match('/ogg$/i', urldecode($checkExtension))) {
5191
                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
5192
5193
                        return $soundPreview;
5194
                    } elseif (
5195
                        //Show preview
5196
                        preg_match('/html$/i', urldecode($checkExtension)) ||
5197
                        preg_match('/htm$/i', urldecode($checkExtension)) ||
5198
                        preg_match('/swf$/i', urldecode($checkExtension)) ||
5199
                        preg_match('/png$/i', urldecode($checkExtension)) ||
5200
                        preg_match('/gif$/i', urldecode($checkExtension)) ||
5201
                        preg_match('/jpg$/i', urldecode($checkExtension)) ||
5202
                        preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5203
                        preg_match('/bmp$/i', urldecode($checkExtension)) ||
5204
                        preg_match('/svg$/i', urldecode($checkExtension))
5205
                    ) {
5206
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id']; //without preview
5207
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5208
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5209
                        '</a>';
5210
                    } else {
5211
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5212
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5213
                        '</a>';
5214
                    }
5215
                } else {
5216
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
5217
                        self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5218
                    '</a>';
5219
                }
5220
            }
5221
        }
5222
    }
5223
5224
    /**
5225
     * Builds an img html tag for the file type.
5226
     *
5227
     * @param string $type            (file/folder)
5228
     * @param string $path
5229
     * @param bool   $isAllowedToEdit
5230
     *
5231
     * @return string img html tag
5232
     */
5233
    public static function build_document_icon_tag($type, $path, $isAllowedToEdit = null)
5234
    {
5235
        $basename = basename($path);
5236
        $sessionId = api_get_session_id();
5237
        if (is_null($isAllowedToEdit)) {
5238
            $isAllowedToEdit = api_is_allowed_to_edit(null, true);
5239
        }
5240
        $user_image = false;
5241
        if ($type == 'file') {
5242
            $icon = choose_image($basename);
5243
            $basename = substr(strrchr($basename, '.'), 1);
5244
        } elseif ($type == 'link') {
5245
            $icon = 'clouddoc.png';
5246
            $basename = get_lang('CloudFileLink');
5247
        } else {
5248
            if ($path == '/shared_folder') {
5249
                $icon = 'folder_users.png';
5250
                if ($isAllowedToEdit) {
5251
                    $basename = get_lang('HelpUsersFolder');
5252
                } else {
5253
                    $basename = get_lang('UserFolders');
5254
                }
5255
            } elseif (strstr($basename, 'sf_user_')) {
5256
                $userInfo = api_get_user_info(substr($basename, 8));
5257
                $icon = $userInfo['avatar_small'];
5258
                $basename = get_lang('UserFolder').' '.$userInfo['complete_name'];
5259
                $user_image = true;
5260
            } elseif (strstr($path, 'shared_folder_session_')) {
5261
                $sessionName = api_get_session_name($sessionId);
5262
                if ($isAllowedToEdit) {
5263
                    $basename = '***('.$sessionName.')*** '.get_lang('HelpUsersFolder');
5264
                } else {
5265
                    $basename = get_lang('UserFolders').' ('.$sessionName.')';
5266
                }
5267
                $icon = 'folder_users.png';
5268
            } else {
5269
                $icon = 'folder_document.png';
5270
5271
                if ($path == '/audio') {
5272
                    $icon = 'folder_audio.png';
5273
                    if ($isAllowedToEdit) {
5274
                        $basename = get_lang('HelpDefaultDirDocuments');
5275
                    } else {
5276
                        $basename = get_lang('Audio');
5277
                    }
5278
                } elseif ($path == '/flash') {
5279
                    $icon = 'folder_flash.png';
5280
                    if ($isAllowedToEdit) {
5281
                        $basename = get_lang('HelpDefaultDirDocuments');
5282
                    } else {
5283
                        $basename = get_lang('Flash');
5284
                    }
5285
                } elseif ($path == '/images') {
5286
                    $icon = 'folder_images.png';
5287
                    if ($isAllowedToEdit) {
5288
                        $basename = get_lang('HelpDefaultDirDocuments');
5289
                    } else {
5290
                        $basename = get_lang('Images');
5291
                    }
5292
                } elseif ($path == '/video') {
5293
                    $icon = 'folder_video.png';
5294
                    if ($isAllowedToEdit) {
5295
                        $basename = get_lang('HelpDefaultDirDocuments');
5296
                    } else {
5297
                        $basename = get_lang('Video');
5298
                    }
5299
                } elseif ($path == '/images/gallery') {
5300
                    $icon = 'folder_gallery.png';
5301
                    if ($isAllowedToEdit) {
5302
                        $basename = get_lang('HelpDefaultDirDocuments');
5303
                    } else {
5304
                        $basename = get_lang('Gallery');
5305
                    }
5306
                } elseif ($path == '/chat_files') {
5307
                    $icon = 'folder_chat.png';
5308
                    if ($isAllowedToEdit) {
5309
                        $basename = get_lang('HelpFolderChat');
5310
                    } else {
5311
                        $basename = get_lang('ChatFiles');
5312
                    }
5313
                } elseif ($path == '/learning_path') {
5314
                    $icon = 'folder_learningpath.png';
5315
                    if ($isAllowedToEdit) {
5316
                        $basename = get_lang('HelpFolderLearningPaths');
5317
                    } else {
5318
                        $basename = get_lang('LearningPaths');
5319
                    }
5320
                }
5321
            }
5322
        }
5323
5324
        if ($user_image) {
5325
            return Display::img($icon, $basename, [], false);
5326
        }
5327
5328
        return Display::return_icon($icon, $basename, [], ICON_SIZE_SMALL);
5329
    }
5330
5331
    /**
5332
     * Creates the row of edit icons for a file/folder.
5333
     *
5334
     * @param array $document_data
5335
     * @param int   $id
5336
     * @param bool  $is_template
5337
     * @param int   $is_read_only
5338
     * @param int   $visibility    (1/0)
5339
     *
5340
     * @return string html img tags with hyperlinks
5341
     */
5342
    public static function build_edit_icons($document_data, $id, $is_template, $is_read_only = 0, $visibility)
5343
    {
5344
        $sessionId = api_get_session_id();
5345
        $courseParams = api_get_cidreq();
5346
        $document_id = $document_data['id'];
5347
        $type = $document_data['filetype'];
5348
        $is_read_only = $document_data['readonly'];
5349
        $path = $document_data['path'];
5350
5351
        if ($type == 'link') {
5352
            $parent_id = self::get_document_id(
5353
                api_get_course_info(),
5354
                rtrim($path, '/'),
5355
                0
5356
            );
5357
        } else {
5358
            $parent_id = self::get_document_id(
5359
                api_get_course_info(),
5360
                dirname($path),
5361
                0
5362
            );
5363
        }
5364
5365
        if (empty($parent_id) && !empty($sessionId)) {
5366
            $parent_id = self::get_document_id(
5367
                api_get_course_info(),
5368
                dirname($path),
5369
                $sessionId
5370
            );
5371
        }
5372
5373
        $curdirpath = dirname($document_data['path']);
5374
        $is_certificate_mode = self::is_certificate_mode($path);
5375
        $curdirpath = urlencode($curdirpath);
5376
        $extension = pathinfo($path, PATHINFO_EXTENSION);
5377
        //@todo Implement remote support for converter
5378
        $usePpt2lp = api_get_setting('service_ppt2lp', 'active') == 'true' && api_get_setting('service_ppt2lp', 'host') == 'localhost';
5379
        $formatTypeList = self::getFormatTypeListConvertor('from', $extension);
5380
        $formatType = current($formatTypeList);
5381
5382
        // If document is read only *or* we're in a session and the document
5383
        // is from a non-session context, hide the edition capabilities
5384
        $modify_icons = [];
5385
        $modify_icons[] = self::getButtonEdit($is_read_only, $document_data, $extension, $is_certificate_mode);
5386
        $modify_icons[] = self::getButtonMove($is_read_only, $document_data, $is_certificate_mode, $parent_id);
5387
        $modify_icons[] = self::getButtonVisibility(
5388
            $is_read_only,
5389
            $visibility,
5390
            $document_data,
5391
            $is_certificate_mode,
5392
            $parent_id
5393
        );
5394
        $modify_icons[] = self::getButtonDelete(
5395
            $is_read_only,
5396
            $document_data,
5397
            $is_certificate_mode,
5398
            $curdirpath,
5399
            $parent_id
5400
        );
5401
5402
        if (!$is_read_only /* or ($session_id!=api_get_session_id()) */) {
5403
            // Add action to covert to PDF, will create a new document whit same filename but .pdf extension
5404
            // @TODO: add prompt to select a format target
5405
            if (!in_array($path, self::get_system_folders())) {
5406
                if ($usePpt2lp && $formatType) {
5407
                    $modify_icons[] = Display::url(
5408
                        Display::return_icon('convert.png', get_lang('Convert')),
5409
                        '#',
5410
                        ['class' => 'convertAction', 'data-documentId' => $document_id, 'data-formatType' => $formatType]
5411
                    );
5412
                }
5413
            }
5414
        }
5415
5416
        if ($type == 'file' && ($extension == 'html' || $extension == 'htm')) {
5417
            if ($is_template == 0) {
5418
                if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] != '/certificates') || !isset($_GET['curdirpath'])) {
5419
                    $modify_icons[] = Display::url(
5420
                        Display::return_icon('wizard.png', get_lang('AddAsTemplate')),
5421
                        api_get_self()."?$courseParams&curdirpath=$curdirpath&add_as_template=$id"
5422
                    );
5423
                }
5424
                if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] == '/certificates') || $is_certificate_mode) {//allow attach certificate to course
5425
                    $visibility_icon_certificate = 'nocertificate';
5426
                    if (self::get_default_certificate_id(api_get_course_id()) == $id) {
5427
                        $visibility_icon_certificate = 'certificate';
5428
                        $certificate = get_lang('DefaultCertificate');
5429
                        $preview = get_lang('PreviewCertificate');
5430
                        $is_preview = true;
5431
                    } else {
5432
                        $is_preview = false;
5433
                        $certificate = get_lang('NoDefaultCertificate');
5434
                    }
5435
                    if (isset($_GET['selectcat'])) {
5436
                        $modify_icons[] = Display::url(
5437
                            Display::return_icon($visibility_icon_certificate.'.png', $certificate),
5438
                            api_get_self()."?$courseParams&curdirpath=$curdirpath&selectcat=".intval($_GET['selectcat'])."&set_certificate=$id"
5439
                        );
5440
                        if ($is_preview) {
5441
                            $modify_icons[] = Display::url(
5442
                                Display::return_icon('preview_view.png', $preview),
5443
                                api_get_self()."?$courseParams&curdirpath=$curdirpath&set_preview=$id"
5444
                            );
5445
                        }
5446
                    }
5447
                }
5448
            } else {
5449
                $modify_icons[] = Display::url(
5450
                    Display::return_icon('wizard_na.png', get_lang('RemoveAsTemplate')),
5451
                    api_get_self()."?$courseParams&curdirpath=$curdirpath&remove_as_template=$id"
5452
                );
5453
            }
5454
5455
            $modify_icons[] = Display::url(
5456
                Display::return_icon('pdf.png', get_lang('Export2PDF')),
5457
                api_get_self()."?$courseParams&action=export_to_pdf&id=$id&curdirpath=$curdirpath"
5458
            );
5459
        }
5460
5461
        return implode(PHP_EOL, $modify_icons);
5462
    }
5463
5464
    /**
5465
     * @param $folders
5466
     * @param $curdirpath
5467
     * @param $move_file
5468
     * @param string $group_dir
5469
     *
5470
     * @return string
5471
     */
5472
    public static function build_move_to_selector($folders, $curdirpath, $move_file, $group_dir = '')
5473
    {
5474
        $form = new FormValidator('move_to', 'post', api_get_self().'?'.api_get_cidreq());
5475
5476
        // Form title
5477
        $form->addHidden('move_file', $move_file);
5478
5479
        $options = [];
5480
5481
        // Group documents cannot be uploaded in the root
5482
        if ($group_dir == '') {
5483
            if ($curdirpath != '/') {
5484
                $options['/'] = get_lang('Documents');
5485
            }
5486
5487
            if (is_array($folders)) {
5488
                foreach ($folders as &$folder) {
5489
                    // Hide some folders
5490
                    if ($folder == '/HotPotatoes_files' ||
5491
                        $folder == '/certificates' ||
5492
                        basename($folder) == 'css'
5493
                    ) {
5494
                        continue;
5495
                    }
5496
                    // Admin setting for Hide/Show the folders of all users
5497
                    if (api_get_setting('show_users_folders') == 'false' &&
5498
                        (strstr($folder, '/shared_folder') || strstr($folder, 'shared_folder_session_'))
5499
                    ) {
5500
                        continue;
5501
                    }
5502
5503
                    // Admin setting for Hide/Show Default folders to all users
5504
                    if (api_get_setting('show_default_folders') == 'false' &&
5505
                        (
5506
                            $folder == '/images' ||
5507
                            $folder == '/flash' ||
5508
                            $folder == '/audio' ||
5509
                            $folder == '/video' ||
5510
                            strstr($folder, '/images/gallery') ||
5511
                            $folder == '/video/flv'
5512
                        )
5513
                    ) {
5514
                        continue;
5515
                    }
5516
5517
                    // Admin setting for Hide/Show chat history folder
5518
                    if (api_get_setting('show_chat_folder') == 'false' &&
5519
                        $folder == '/chat_files') {
5520
                        continue;
5521
                    }
5522
5523
                    // You cannot move a file to:
5524
                    // 1. current directory
5525
                    // 2. inside the folder you want to move
5526
                    // 3. inside a subfolder of the folder you want to move
5527
                    if (($curdirpath != $folder) &&
5528
                        ($folder != $move_file) &&
5529
                        (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
5530
                    ) {
5531
                        $path_displayed = $folder;
5532
                        // If document title is used, we have to display titles instead of real paths...
5533
                        $path_displayed = self::get_titles_of_path($folder);
5534
5535
                        if (empty($path_displayed)) {
5536
                            $path_displayed = get_lang('Untitled');
5537
                        }
5538
                        $options[$folder] = $path_displayed;
5539
                    }
5540
                }
5541
            }
5542
        } else {
5543
            foreach ($folders as $folder) {
5544
                if (($curdirpath != $folder) &&
5545
                    ($folder != $move_file) &&
5546
                    (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
5547
                ) {
5548
                    // Cannot copy dir into his own subdir
5549
                    $path_displayed = self::get_titles_of_path($folder);
5550
                    $display_folder = substr($path_displayed, strlen($group_dir));
5551
                    $display_folder = ($display_folder == '') ? get_lang('Documents') : $display_folder;
5552
                    //$form .= '<option value="'.$folder.'">'.$display_folder.'</option>';
5553
                    $options[$folder] = $display_folder;
5554
                }
5555
            }
5556
        }
5557
        $form->addElement('select', 'move_to', get_lang('MoveTo'), $options);
5558
        $form->addButtonNext(get_lang('MoveElement'), 'move_file_submit');
5559
5560
        return $form->returnForm();
5561
    }
5562
5563
    /**
5564
     * Gets the path translated with title of docs and folders.
5565
     *
5566
     * @param string $path the real path
5567
     *
5568
     * @return the path which should be displayed
5569
     */
5570
    public static function get_titles_of_path($path)
5571
    {
5572
        global $tmp_folders_titles;
5573
        $course_id = api_get_course_int_id();
5574
        $nb_slashes = substr_count($path, '/');
5575
        $current_slash_pos = 0;
5576
        $path_displayed = '';
5577
        for ($i = 0; $i < $nb_slashes; $i++) {
5578
            // For each folder of the path, retrieve title.
5579
            $current_slash_pos = strpos($path, '/', $current_slash_pos + 1);
5580
            $tmp_path = substr($path, strpos($path, '/', 0), $current_slash_pos);
5581
5582
            if (empty($tmp_path)) {
5583
                // If empty, then we are in the final part of the path
5584
                $tmp_path = $path;
5585
            }
5586
5587
            if (!empty($tmp_folders_titles[$tmp_path])) {
5588
                // If this path has soon been stored here we don't need a new query
5589
                $path_displayed .= $tmp_folders_titles[$tmp_path];
5590
            } else {
5591
                $sql = 'SELECT title FROM '.Database::get_course_table(TABLE_DOCUMENT).'
5592
                        WHERE c_id = '.$course_id.' AND path LIKE BINARY "'.$tmp_path.'"';
5593
                $rs = Database::query($sql);
5594
                $tmp_title = '/'.Database::result($rs, 0, 0);
5595
                $path_displayed .= $tmp_title;
5596
                $tmp_folders_titles[$tmp_path] = $tmp_title;
5597
            }
5598
        }
5599
5600
        return $path_displayed;
5601
    }
5602
5603
    /**
5604
     * Creates form that asks for the directory name.
5605
     *
5606
     * @return string html-output text for the form
5607
     */
5608
    public static function create_dir_form($dirId)
5609
    {
5610
        global $document_id;
5611
        $form = new FormValidator('create_dir_form', 'post', api_get_self().'?'.api_get_cidreq());
5612
        $form->addElement('hidden', 'create_dir', 1);
5613
        $form->addElement('hidden', 'dir_id', intval($document_id));
5614
        $form->addElement('hidden', 'id', intval($dirId));
5615
        $form->addElement('header', get_lang('CreateDir'));
5616
        $form->addText('dirname', get_lang('NewDir'), ['autofocus' => 'autofocus']);
5617
        $form->addButtonCreate(get_lang('CreateFolder'));
5618
5619
        return $form->returnForm();
5620
    }
5621
5622
    /**
5623
     * Checks whether the user is in shared folder.
5624
     *
5625
     * @param string $curdirpath
5626
     * @param int    $sessionId
5627
     *
5628
     * @return bool Return true when user is into shared folder
5629
     */
5630
    public static function is_shared_folder($curdirpath, $sessionId)
5631
    {
5632
        $clean_curdirpath = Security::remove_XSS($curdirpath);
5633
        if ($clean_curdirpath == '/shared_folder') {
5634
            return true;
5635
        } elseif ($clean_curdirpath == '/shared_folder_session_'.$sessionId) {
5636
            return true;
5637
        } else {
5638
            return false;
5639
        }
5640
    }
5641
5642
    /**
5643
     * Checks whether the user is into any user shared folder.
5644
     *
5645
     * @param string $path
5646
     * @param int    $sessionId
5647
     *
5648
     * @return bool Return true when user is in any user shared folder
5649
     */
5650
    public static function is_any_user_shared_folder($path, $sessionId)
5651
    {
5652
        $clean_path = Security::remove_XSS($path);
5653
        if (strpos($clean_path, 'shared_folder/sf_user_')) {
5654
            return true;
5655
        } elseif (strpos($clean_path, 'shared_folder_session_'.$sessionId.'/sf_user_')) {
5656
            return true;
5657
        } else {
5658
            return false;
5659
        }
5660
    }
5661
5662
    /**
5663
     * Create users shared folder for course.
5664
     *
5665
     * @param int   $userId
5666
     * @param array $courseInfo
5667
     * @param int   $sessionId
5668
     */
5669
    public static function createUserSharedFolder($userId, array $courseInfo, $sessionId = 0)
5670
    {
5671
        $documentDirectory = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document';
5672
        $userInfo = api_get_user_info($userId);
5673
5674
        if (!$sessionId) {
5675
            //Create shared folder. Necessary for recycled courses.
5676
            if (!file_exists($documentDirectory.'/shared_folder')) {
5677
                create_unexisting_directory(
5678
                    $courseInfo,
5679
                    $userId,
5680
                    0,
5681
                    0,
5682
                    0,
5683
                    $documentDirectory,
5684
                    '/shared_folder',
5685
                    get_lang('UserFolders'),
5686
                    0,
5687
                    false,
5688
                    false
5689
                );
5690
            }
5691
            // Create dynamic user shared folder
5692
            if (!file_exists($documentDirectory.'/shared_folder/sf_user_'.$userId)) {
5693
                create_unexisting_directory(
5694
                    $courseInfo,
5695
                    $userId,
5696
                    0,
5697
                    0,
5698
                    0,
5699
                    $documentDirectory,
5700
                    '/shared_folder/sf_user_'.$userId,
5701
                    $userInfo['complete_name'],
5702
                    1,
5703
                    false,
5704
                    false
5705
                );
5706
            }
5707
5708
            return;
5709
        }
5710
5711
        // Create shared folder session.
5712
        if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId)) {
5713
            create_unexisting_directory(
5714
                $courseInfo,
5715
                api_get_user_id(),
5716
                $sessionId,
5717
                0,
5718
                0,
5719
                $documentDirectory,
5720
                '/shared_folder_session_'.$sessionId,
5721
                get_lang('UserFolders').' ('.api_get_session_name($sessionId).')',
5722
                0,
5723
                false,
5724
                false
5725
            );
5726
        }
5727
        //Create dynamic user shared folder into a shared folder session
5728
        if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId.'/sf_user_'.$userId)) {
5729
            create_unexisting_directory(
5730
                $courseInfo,
5731
                $userId,
5732
                $sessionId,
5733
                0,
5734
                0,
5735
                $documentDirectory,
5736
                '/shared_folder_session_'.$sessionId.'/sf_user_'.$userId,
5737
                $userInfo['complete_name'].'('.api_get_session_name($sessionId).')',
5738
                1,
5739
                false,
5740
                false
5741
            );
5742
        }
5743
    }
5744
5745
    /**
5746
     * Checks whether the user is into his shared folder or into a subfolder.
5747
     *
5748
     * @param int    $user_id
5749
     * @param string $path
5750
     * @param int    $sessionId
5751
     *
5752
     * @return bool Return true when user is in his user shared folder or into a subfolder
5753
     */
5754
    public static function is_my_shared_folder($user_id, $path, $sessionId)
5755
    {
5756
        $clean_path = Security::remove_XSS($path).'/';
5757
        //for security does not remove the last slash
5758
        $main_user_shared_folder = '/shared_folder\/sf_user_'.$user_id.'\//';
5759
        //for security does not remove the last slash
5760
        $main_user_shared_folder_session = '/shared_folder_session_'.$sessionId.'\/sf_user_'.$user_id.'\//';
5761
5762
        if (preg_match($main_user_shared_folder, $clean_path)) {
5763
            return true;
5764
        } elseif (preg_match($main_user_shared_folder_session, $clean_path)) {
5765
            return true;
5766
        } else {
5767
            return false;
5768
        }
5769
    }
5770
5771
    /**
5772
     * Check if the file name or folder searched exist.
5773
     *
5774
     * @return bool Return true when exist
5775
     */
5776
    public static function search_keyword($document_name, $keyword)
5777
    {
5778
        if (api_strripos($document_name, $keyword) !== false) {
5779
            return true;
5780
        } else {
5781
            return false;
5782
        }
5783
    }
5784
5785
    /**
5786
     * Checks whether a document can be previewed by using the browser.
5787
     *
5788
     * @param string $file_extension the filename extension of the document (it must be in lower case)
5789
     *
5790
     * @return bool returns TRUE or FALSE
5791
     */
5792
    public static function isBrowserViewable($file_extension)
5793
    {
5794
        static $allowed_extensions = [
5795
            'htm', 'html', 'xhtml',
5796
            'gif', 'jpg', 'jpeg', 'png', 'tif', 'tiff',
5797
            'pdf', 'svg', 'swf',
5798
            'txt', 'log',
5799
            'mp4', 'ogg', 'ogv', 'ogx', 'mpg', 'mpeg', 'mov', 'avi', 'webm', 'wmv',
5800
            'mp3', 'oga', 'wav', 'au', 'wma', 'mid', 'kar',
5801
        ];
5802
5803
        /*
5804
          //TODO: make a admin switch to strict mode
5805
          1. global default $allowed_extensions
5806
          if (in_array($file_extension, $allowed_extensions)) { // Assignment + a logical check.
5807
          return true;
5808
          }
5809
          2. check native support
5810
          3. check plugins: quicktime, mediaplayer, vlc, acrobat, flash, java
5811
         */
5812
5813
        if (!($result = in_array($file_extension, $allowed_extensions))) {
5814
            // Assignment + a logical check.
5815
            return false;
5816
        }
5817
5818
        //check native support (Explorer, Opera, Firefox, Chrome, Safari)
5819
        if ($file_extension == "pdf") {
5820
            return api_browser_support('pdf');
5821
        } elseif ($file_extension == "mp3") {
5822
            return api_browser_support('mp3');
5823
        } elseif ($file_extension == "mp4") {
5824
            return api_browser_support('mp4');
5825
        } elseif ($file_extension == "ogg" || $file_extension == "ogx" || $file_extension == "ogv" || $file_extension == "oga") {
5826
            return api_browser_support('ogg');
5827
        } elseif ($file_extension == "svg") {
5828
            return api_browser_support('svg');
5829
        } elseif ($file_extension == "mpg" || $file_extension == "mpeg") {
5830
            return api_browser_support('mpg');
5831
        } elseif ($file_extension == "mov") {
5832
            return api_browser_support('mov');
5833
        } elseif ($file_extension == "wav") {
5834
            return api_browser_support('wav');
5835
        } elseif ($file_extension == "mid" || $file_extension == "kar") {
5836
            return api_browser_support('mid');
5837
        } elseif ($file_extension == "avi") {
5838
            return api_browser_support('avi');
5839
        } elseif ($file_extension == "wma") {
5840
            return api_browser_support('wma');
5841
        } elseif ($file_extension == "wmv") {
5842
            return api_browser_support('wmv');
5843
        } elseif ($file_extension == "tif" || $file_extension == "tiff") {
5844
            return api_browser_support('tif');
5845
        } elseif ($file_extension == "mov") {
5846
            return api_browser_support('mov');
5847
        } elseif ($file_extension == "au") {
5848
            return api_browser_support('au');
5849
        } elseif ($file_extension == "webm") {
5850
            return api_browser_support('webm');
5851
        }
5852
5853
        return $result;
5854
    }
5855
5856
    /**
5857
     * @param array $courseInfo
5858
     * @param int   $sessionId
5859
     *
5860
     * @return array
5861
     */
5862
    public static function getDeletedDocuments($courseInfo, $sessionId = 0)
5863
    {
5864
        $table = Database::get_course_table(TABLE_DOCUMENT);
5865
        $courseId = $courseInfo['real_id'];
5866
        $sessionCondition = api_get_session_condition($sessionId);
5867
        $sql = "SELECT * FROM $table
5868
                WHERE
5869
                  path LIKE '%DELETED%' AND
5870
                  c_id = $courseId
5871
                  $sessionCondition
5872
                ORDER BY path
5873
        ";
5874
5875
        $result = Database::query($sql);
5876
        $files = [];
5877
        while ($document = Database::fetch_array($result, 'ASSOC')) {
5878
            $files[] = $document;
5879
        }
5880
5881
        return $files;
5882
    }
5883
5884
    /**
5885
     * @param int   $id
5886
     * @param array $courseInfo
5887
     * @param int   $sessionId
5888
     *
5889
     * @return array
5890
     */
5891
    public static function getDeletedDocument($id, $courseInfo, $sessionId = 0)
5892
    {
5893
        if (empty($courseInfo)) {
5894
            return false;
5895
        }
5896
5897
        $table = Database::get_course_table(TABLE_DOCUMENT);
5898
        $courseId = $courseInfo['real_id'];
5899
        $sessionCondition = api_get_session_condition($sessionId);
5900
        $sql = "SELECT * FROM $table
5901
                WHERE
5902
                  path LIKE '%DELETED%' AND
5903
                  id = $id AND
5904
                  c_id = $courseId
5905
                  $sessionCondition
5906
                LIMIT 1
5907
        ";
5908
        $result = Database::query($sql);
5909
        if (Database::num_rows($result)) {
5910
            $result = Database::fetch_array($result, 'ASSOC');
5911
5912
            return $result;
5913
        }
5914
5915
        return [];
5916
    }
5917
5918
    /**
5919
     * @param int   $id
5920
     * @param array $courseInfo
5921
     * @param int   $sessionId
5922
     *
5923
     * @return bool
5924
     */
5925
    public static function purgeDocument($id, $courseInfo, $sessionId = 0)
5926
    {
5927
        $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
5928
        if (!empty($document)) {
5929
            $path = $document['path'];
5930
            $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
5931
            my_delete($coursePath.$path);
5932
            // Hard delete.
5933
            self::deleteDocumentFromDb($id, $courseInfo, $sessionId, true);
5934
5935
            return true;
5936
        }
5937
5938
        return false;
5939
    }
5940
5941
    /**
5942
     * @param array $courseInfo
5943
     * @param int   $sessionId
5944
     */
5945
    public static function purgeDocuments($courseInfo, $sessionId)
5946
    {
5947
        $files = self::getDeletedDocuments($courseInfo, $sessionId);
5948
        foreach ($files as $file) {
5949
            self::purgeDocument($file['id'], $courseInfo, $sessionId);
5950
        }
5951
    }
5952
5953
    /**
5954
     * @param int   $id
5955
     * @param array $courseInfo
5956
     * @param int   $sessionId
5957
     */
5958
    public static function downloadDeletedDocument($id, $courseInfo, $sessionId)
5959
    {
5960
        $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
5961
        if (!empty($document)) {
5962
            $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
5963
5964
            if (Security::check_abs_path($coursePath.$document['path'], $coursePath)) {
5965
                self::file_send_for_download($coursePath.$document['path']);
5966
                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...
5967
            }
5968
        }
5969
    }
5970
5971
    /**
5972
     * @param array $courseInfo
5973
     * @param int   $sessionId
5974
     *
5975
     * @return bool
5976
     */
5977
    public static function downloadAllDeletedDocument($courseInfo, $sessionId)
5978
    {
5979
        $files = self::getDeletedDocuments($courseInfo, $sessionId);
5980
5981
        if (empty($files)) {
5982
            return false;
5983
        }
5984
5985
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
5986
5987
        // Creating a ZIP file.
5988
        $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
5989
        $zip = new PclZip($tempZipFile);
5990
        foreach ($files as $file) {
5991
            $zip->add(
5992
                $coursePath.$file['path'],
5993
                PCLZIP_OPT_REMOVE_PATH,
5994
                $coursePath
5995
            );
5996
        }
5997
5998
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
5999
            self::file_send_for_download($tempZipFile, true);
6000
            @unlink($tempZipFile);
6001
            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...
6002
        }
6003
    }
6004
6005
    /**
6006
     * Delete documents from a session in a course.
6007
     *
6008
     * @param array $courseInfo
6009
     * @param int   $sessionId
6010
     *
6011
     * @return bool
6012
     */
6013
    public static function deleteDocumentsFromSession($courseInfo, $sessionId)
6014
    {
6015
        if (empty($courseInfo)) {
6016
            return false;
6017
        }
6018
6019
        if (empty($sessionId)) {
6020
            return false;
6021
        }
6022
6023
        $itemPropertyTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
6024
        $documentTable = Database::get_course_table(TABLE_DOCUMENT);
6025
6026
        $conditionSession = api_get_session_condition($sessionId, true, false, 'd.session_id');
6027
        $courseId = $courseInfo['real_id'];
6028
6029
        // get invisible folders
6030
        $sql = "SELECT DISTINCT d.id, path
6031
                FROM $itemPropertyTable i
6032
                INNER JOIN $documentTable d
6033
                ON (i.c_id = d.c_id)
6034
                WHERE
6035
                    d.id = i.ref AND
6036
                    i.tool = '".TOOL_DOCUMENT."'
6037
                    $conditionSession AND
6038
                    i.c_id = $courseId AND
6039
                    d.c_id = $courseId ";
6040
6041
        $result = Database::query($sql);
6042
        $documents = Database::store_result($result, 'ASSOC');
6043
        if ($documents) {
6044
            $course_dir = $courseInfo['directory'].'/document';
6045
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
6046
            $base_work_dir = $sys_course_path.$course_dir;
6047
6048
            foreach ($documents as $document) {
6049
                $documentId = $document['id'];
6050
                self::delete_document(
6051
                    $courseInfo,
6052
                    null,
6053
                    $base_work_dir,
6054
                    $sessionId,
6055
                    $documentId
6056
                );
6057
            }
6058
        }
6059
6060
        $sql = "DELETE FROM $documentTable
6061
                WHERE c_id = $courseId AND session_id = $sessionId";
6062
        Database::query($sql);
6063
6064
        $sql = "DELETE FROM $itemPropertyTable
6065
                WHERE c_id = $courseId AND session_id = $sessionId AND tool = '".TOOL_DOCUMENT."'";
6066
        Database::query($sql);
6067
    }
6068
6069
    /**
6070
     * Update the file or directory path in the document db document table.
6071
     *
6072
     * @author - Hugues Peeters <[email protected]>
6073
     *
6074
     * @param string $action   - action type require : 'delete' or 'update'
6075
     * @param string $old_path - old path info stored to change
6076
     * @param string $new_path - new path info to substitute
6077
     *
6078
     * @desc Update the file or directory path in the document db document table
6079
     */
6080
    public static function updateDbInfo($action, $old_path, $new_path = '')
6081
    {
6082
        $dbTable = Database::get_course_table(TABLE_DOCUMENT);
6083
        $course_id = api_get_course_int_id();
6084
        $old_path = Database::escape_string($old_path);
6085
        switch ($action) {
6086
            case 'delete':
6087
                $query = "DELETE FROM $dbTable
6088
                          WHERE
6089
                            c_id = $course_id AND
6090
                            (
6091
                                path LIKE BINARY '".$old_path."' OR
6092
                                path LIKE BINARY '".$old_path."/%'
6093
                            )";
6094
                Database::query($query);
6095
                break;
6096
            case 'update':
6097
                if ($new_path[0] == '.') {
6098
                    $new_path = substr($new_path, 1);
6099
                }
6100
                $new_path = str_replace('//', '/', $new_path);
6101
6102
                // Attempt to update	- tested & working for root	dir
6103
                $new_path = Database::escape_string($new_path);
6104
                $query = "UPDATE $dbTable SET
6105
                            path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
6106
                          WHERE 
6107
                                c_id = $course_id AND 
6108
                                (path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%')";
6109
                Database::query($query);
6110
                break;
6111
        }
6112
    }
6113
6114
    /**
6115
     * This function calculates the resized width and resized heigt
6116
     * according to the source and target widths
6117
     * and heights, height so that no distortions occur
6118
     * parameters.
6119
     *
6120
     * @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...
6121
     * @param $target_width = how large do you want your resized image
6122
     * @param $target_height = how large do you want your resized image
6123
     * @param $slideshow (default=0) =
6124
     *      indicates weither we are generating images for a slideshow or not,
6125
     *		this overrides the $_SESSION["image_resizing"] a bit so that a thumbnail
6126
     *	    view is also possible when you choose not to resize the source images
6127
     *
6128
     * @return array
6129
     */
6130
    public static function resizeImageSlideShow(
6131
        $image,
6132
        $target_width,
6133
        $target_height,
6134
        $slideshow = 0
6135
    ) {
6136
        // Modifications by Ivan Tcholakov, 04-MAY-2009.
6137
        $result = [];
6138
        $imageResize = Session::read('image_resizing');
6139
        if ($imageResize == 'resizing' || $slideshow == 1) {
6140
            $new_sizes = api_resize_image($image, $target_width, $target_height);
6141
            $result[] = $new_sizes['height'];
6142
            $result[] = $new_sizes['width'];
6143
        } else {
6144
            $size = api_getimagesize($image);
6145
            $result[] = $size['height'];
6146
            $result[] = $size['width'];
6147
        }
6148
6149
        return $result;
6150
    }
6151
6152
    /**
6153
     * Calculates the total size of a directory by adding the sizes (that
6154
     * are stored in the database) of all files & folders in this directory.
6155
     *
6156
     * @param string $path
6157
     * @param bool   $can_see_invisible
6158
     *
6159
     * @return int Total size
6160
     */
6161
    public static function getTotalFolderSize($path, $can_see_invisible = false)
6162
    {
6163
        $table_itemproperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6164
        $table_document = Database::get_course_table(TABLE_DOCUMENT);
6165
        $tool_document = TOOL_DOCUMENT;
6166
6167
        $course_id = api_get_course_int_id();
6168
        $session_id = api_get_session_id();
6169
        $session_condition = api_get_session_condition(
6170
            $session_id,
6171
            true,
6172
            true,
6173
            'props.session_id'
6174
        );
6175
6176
        if (empty($course_id)) {
6177
            return 0;
6178
        }
6179
6180
        $path = Database::escape_string($path);
6181
        $visibility_rule = ' props.visibility '.($can_see_invisible ? '<> 2' : '= 1');
6182
6183
        $sql = "SELECT SUM(table1.size) FROM (
6184
                SELECT props.ref, size
6185
                FROM $table_itemproperty AS props 
6186
                INNER JOIN $table_document AS docs
6187
                ON (docs.id = props.ref AND docs.c_id = props.c_id)
6188
                WHERE
6189
                    docs.c_id = $course_id AND                    
6190
                    docs.path LIKE '$path/%' AND
6191
                    props.c_id = $course_id AND
6192
                    props.tool = '$tool_document' AND
6193
                    $visibility_rule
6194
                    $session_condition
6195
                GROUP BY ref
6196
            ) as table1";
6197
6198
        $result = Database::query($sql);
6199
        if ($result && Database::num_rows($result) != 0) {
6200
            $row = Database::fetch_row($result);
6201
6202
            return $row[0] == null ? 0 : $row[0];
6203
        } else {
6204
            return 0;
6205
        }
6206
    }
6207
6208
    /**
6209
     * Adds a cloud link to the database.
6210
     *
6211
     * @author - Aquilino Blanco Cores <[email protected]>
6212
     *
6213
     * @param array  $_course
6214
     * @param string $path
6215
     * @param string $url
6216
     * @param string $name
6217
     *
6218
     * @return int id of document or 0 if already exists or there was a problem creating it
6219
     */
6220
    public static function addCloudLink($_course, $path, $url, $name)
6221
    {
6222
        $file_path = $path;
6223
        if (!self::cloudLinkExists($_course, $path, $url)) {
6224
            $doc_id = add_document($_course, $file_path, 'link', 0, $name, $url);
6225
            if ($doc_id) {
6226
                // Update document item_property
6227
                api_item_property_update(
6228
                    $_course,
6229
                    TOOL_DOCUMENT,
6230
                    $doc_id,
6231
                    'DocumentAdded',
6232
                    api_get_user_id(),
6233
                    api_get_group_id(),
6234
                    api_get_user_id(),
6235
                    null,
6236
                    null,
6237
                    api_get_session_id()
6238
                );
6239
            }
6240
6241
            // If the file is in a folder, we need to update all parent folders
6242
            item_property_update_on_folder($_course, $file_path, api_get_user_id());
6243
6244
            return $doc_id;
6245
        } else {
6246
            return 0;
6247
        }
6248
    }
6249
6250
    /**
6251
     * Deletes a cloud link from the database.
6252
     *
6253
     * @author - Aquilino Blanco Cores <[email protected]>
6254
     *
6255
     * @param array  $courseInfo
6256
     * @param string $documentId
6257
     *
6258
     * @return bool true if success / false if an error occurred
6259
     */
6260
    public static function deleteCloudLink($courseInfo, $documentId)
6261
    {
6262
        if (empty($documentId) || empty($courseInfo)) {
6263
            return false;
6264
        }
6265
6266
        $documentId = (int) $documentId;
6267
        $fileDeletedFromDb = false;
6268
        if (!empty($documentId)) {
6269
            self::deleteDocumentFromDb($documentId, $courseInfo, 0, true);
6270
            // checking
6271
            $table = Database::get_course_table(TABLE_DOCUMENT);
6272
            $courseId = $courseInfo['real_id'];
6273
            echo $sql = "SELECT * FROM $table WHERE id = $documentId AND c_id = $courseId";
6274
            $result = Database::query($sql);
6275
            $exists = Database::num_rows($result) > 0;
6276
            $fileDeletedFromDb = !$exists;
6277
        }
6278
6279
        return $fileDeletedFromDb;
6280
    }
6281
6282
    /**
6283
     * Gets the id of a cloud link with a given path.
6284
     *
6285
     * @author - Aquilino Blanco Cores <[email protected]>
6286
     *
6287
     * @param array  $courseInfo
6288
     * @param string $path
6289
     * @param string $url
6290
     *
6291
     * @return int link's id / false if no link found
6292
     */
6293
    public static function getCloudLinkId($courseInfo, $path, $url)
6294
    {
6295
        $table = Database::get_course_table(TABLE_DOCUMENT);
6296
6297
        if (empty($courseInfo)) {
6298
            return false;
6299
        }
6300
6301
        $courseId = (int) $courseInfo['real_id'];
6302
        $path = Database::escape_string($path);
6303
6304
        if (substr($path, -1) != '/') {
6305
            // Add final slash to path if not present
6306
            $path .= '/';
6307
        }
6308
6309
        if (!empty($courseId) && !empty($path)) {
6310
            $sql = "SELECT id FROM $table 
6311
                    WHERE 
6312
                        c_id = $courseId AND 
6313
                        path LIKE BINARY '$path' AND 
6314
                        comment = '$url' AND 
6315
                        filetype = 'link' 
6316
                    LIMIT 1";
6317
            $result = Database::query($sql);
6318
            if ($result && Database::num_rows($result)) {
6319
                $row = Database::fetch_array($result);
6320
6321
                return intval($row[0]);
6322
            }
6323
        }
6324
6325
        return false;
6326
    }
6327
6328
    /**
6329
     * Checks if a cloud link exists.
6330
     *
6331
     * @author - Aquilino Blanco Cores <[email protected]>
6332
     *
6333
     * @param array  $courseInfo
6334
     * @param string $path
6335
     * @param string $url
6336
     *
6337
     * @return bool true if it exists false in other case
6338
     */
6339
    public static function cloudLinkExists($courseInfo, $path, $url)
6340
    {
6341
        $exists = self::getCloudLinkId($courseInfo, $path, $url);
6342
6343
        return $exists;
6344
    }
6345
6346
    /**
6347
     * Gets the wellformed URLs regular expression in order to use it on forms' verifications.
6348
     *
6349
     * @author Aquilino Blanco Cores <[email protected]>
6350
     *
6351
     * @return string the well formed URLs regular expressions string
6352
     */
6353
    public static function getWellFormedUrlRegex()
6354
    {
6355
        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';
6356
    }
6357
6358
    /**
6359
     * Gets the files hosting sites' whitelist.
6360
     *
6361
     * @author Aquilino Blanco Cores <[email protected]>
6362
     *
6363
     * @return array the sites list
6364
     */
6365
    public static function getFileHostingWhiteList()
6366
    {
6367
        return [
6368
            'asuswebstorage.com',
6369
            'dropbox.com',
6370
            'dropboxusercontent.com',
6371
            'fileserve.com',
6372
            'drive.google.com',
6373
            'icloud.com',
6374
            'mediafire.com',
6375
            'mega.nz',
6376
            'onedrive.live.com',
6377
            'slideshare.net',
6378
            'scribd.com',
6379
            'wetransfer.com',
6380
            'box.com',
6381
            'livefilestore.com', // OneDrive
6382
        ];
6383
    }
6384
6385
    /**
6386
     * Parse file information into a link.
6387
     *
6388
     * @param array  $userInfo        Current user info
6389
     * @param array  $course_info
6390
     * @param int    $session_id
6391
     * @param array  $resource
6392
     * @param int    $lp_id
6393
     * @param bool   $add_move_button
6394
     * @param string $target
6395
     * @param string $overwrite_url
6396
     *
6397
     * @return null|string
6398
     */
6399
    private static function parseFile(
6400
        $userInfo,
6401
        $course_info,
6402
        $session_id,
6403
        $resource,
6404
        $lp_id,
6405
        $add_move_button,
6406
        $target,
6407
        $overwrite_url
6408
    ) {
6409
        $img_sys_path = api_get_path(SYS_CODE_PATH).'img/';
6410
        $web_code_path = api_get_path(WEB_CODE_PATH);
6411
6412
        $documentId = $resource['id'];
6413
        $path = $resource['path'];
6414
6415
        if (empty($path)) {
6416
            $num = 0;
6417
        } else {
6418
            $num = substr_count($path, '/') - 1;
6419
        }
6420
6421
        // It's a file.
6422
        $icon = choose_image($path);
6423
        $position = strrpos($icon, '.');
6424
        $icon = substr($icon, 0, $position).'_small.gif';
6425
        $my_file_title = $resource['title'];
6426
        $visibility = $resource['visibility'];
6427
6428
        // If title is empty we try to use the path
6429
        if (empty($my_file_title)) {
6430
            $my_file_title = basename($path);
6431
        }
6432
6433
        // Show the "image name" not the filename of the image.
6434
        if ($lp_id) {
6435
            // LP URL
6436
            $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;
6437
            if (!empty($overwrite_url)) {
6438
                $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId.'';
6439
            }
6440
        } else {
6441
            // Direct document URL
6442
            $url = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6443
            if (!empty($overwrite_url)) {
6444
                $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId;
6445
            }
6446
        }
6447
6448
        $img = Display::returnIconPath($icon);
6449
        if (!file_exists($img_sys_path.$icon)) {
6450
            $img = Display::returnIconPath('default_small.gif');
6451
        }
6452
6453
        $link = Display::url(
6454
            '<img alt="" src="'.$img.'" title="" />&nbsp;'.$my_file_title,
6455
            $url,
6456
            ['target' => $target, 'class' => 'moved']
6457
        );
6458
6459
        $directUrl = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6460
        $link .= '&nbsp;'.Display::url(
6461
            Display::return_icon('preview_view.png', get_lang('Preview')),
6462
            $directUrl,
6463
            ['target' => '_blank']
6464
        );
6465
6466
        $visibilityClass = null;
6467
        if ($visibility == 0) {
6468
            $visibilityClass = ' text-muted ';
6469
        }
6470
        $return = null;
6471
6472
        if ($lp_id == false) {
6473
            $return .= '<li class="doc_resource '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6474
        } else {
6475
            $return .= '<li class="doc_resource lp_resource_element '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6476
        }
6477
6478
        $return .= '<div class="item_data" style="margin-left:'.($num * 5).'px;margin-right:5px;">';
6479
        if ($add_move_button) {
6480
            $return .= '<a class="moved" href="#">';
6481
            $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), [], ICON_SIZE_TINY);
6482
            $return .= '</a> ';
6483
        }
6484
        $return .= $link;
6485
        $sessionStar = api_get_session_image($resource['session_id'], $userInfo['status']);
6486
        $return .= $sessionStar;
6487
6488
        $return .= '</div></li>';
6489
6490
        return $return;
6491
    }
6492
6493
    /**
6494
     * @param int   $folderId
6495
     * @param array $resource
6496
     * @param int   $lp_id
6497
     *
6498
     * @return null|string
6499
     */
6500
    private static function parseFolder($folderId, $resource, $lp_id)
6501
    {
6502
        $title = isset($resource['title']) ? $resource['title'] : null;
6503
        $path = isset($resource['path']) ? $resource['path'] : null;
6504
6505
        if (empty($path)) {
6506
            $num = 0;
6507
        } else {
6508
            $num = substr_count($path, '/');
6509
        }
6510
6511
        // It's a folder.
6512
        //hide some folders
6513
        if (in_array(
6514
            $path,
6515
            ['shared_folder', 'chat_files', 'HotPotatoes_files', 'css', 'certificates']
6516
        )) {
6517
            return null;
6518
        } elseif (preg_match('/_groupdocs/', $path)) {
6519
            return null;
6520
        } elseif (preg_match('/sf_user_/', $path)) {
6521
            return null;
6522
        } elseif (preg_match('/shared_folder_session_/', $path)) {
6523
            return null;
6524
        }
6525
6526
        $onclick = '';
6527
        // if in LP, hidden folder are displayed in grey
6528
        $folder_class_hidden = '';
6529
        if ($lp_id) {
6530
            if (isset($resource['visible']) && $resource['visible'] == 0) {
6531
                $folder_class_hidden = "doc_folder_hidden"; // in base.css
6532
            }
6533
            $onclick = 'onclick="javascript: testResources(\'res_'.$resource['id'].'\',\'img_'.$resource['id'].'\')"';
6534
        }
6535
        $return = null;
6536
6537
        if (empty($path)) {
6538
            $return = '<ul class="lp_resource">';
6539
        }
6540
6541
        $return .= '<li class="doc_folder '.$folder_class_hidden.'" id="doc_id_'.$resource['id'].'"  style="margin-left:'.($num * 18).'px; ">';
6542
6543
        $image = Display::returnIconPath('nolines_plus.gif');
6544
        if (empty($path)) {
6545
            $image = Display::returnIconPath('nolines_minus.gif');
6546
        }
6547
        $return .= '<img style="cursor: pointer;" src="'.$image.'" align="absmiddle" id="img_'.$resource['id'].'" '.$onclick.'>';
6548
        $return .= Display::return_icon('lp_folder.gif').'&nbsp;';
6549
        $return .= '<span '.$onclick.' style="cursor: pointer;" >'.$title.'</span>';
6550
        $return .= '</li>';
6551
6552
        if (empty($path)) {
6553
            if ($folderId == false) {
6554
                $return .= '<div id="res_'.$resource['id'].'" >';
6555
            } else {
6556
                $return .= '<div id="res_'.$resource['id'].'" style="display: none;" >';
6557
            }
6558
        }
6559
6560
        return $return;
6561
    }
6562
6563
    /**
6564
     * Get the button to edit document.
6565
     *
6566
     * @param bool   $isReadOnly
6567
     * @param array  $documentData
6568
     * @param string $extension
6569
     * @param bool   $isCertificateMode
6570
     *
6571
     * @return string
6572
     */
6573
    private static function getButtonEdit($isReadOnly, array $documentData, $extension, $isCertificateMode)
6574
    {
6575
        $extension = strtolower($extension);
6576
        $iconEn = Display::return_icon('edit.png', get_lang('Modify'));
6577
        $iconDis = Display::return_icon('edit_na.png', get_lang('Modify'));
6578
        $courseParams = api_get_cidreq();
6579
        $webOdfExtensionList = self::get_web_odf_extension_list();
6580
        $path = $documentData['path'];
6581
        $document_id = $documentData['id'];
6582
6583
        if ($isReadOnly) {
6584
            if (!api_is_course_admin() && !api_is_platform_admin()) {
6585
                return $iconDis;
6586
            }
6587
6588
            if (
6589
                $extension == 'svg' && api_browser_support('svg') &&
6590
                api_get_setting('enabled_support_svg') == 'true'
6591
            ) {
6592
                return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
6593
            }
6594
6595
            if (
6596
                in_array($extension, $webOdfExtensionList) &&
6597
                api_get_configuration_value('enabled_support_odf') === true
6598
            ) {
6599
                return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
6600
            }
6601
6602
            if (
6603
                in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6604
                    api_get_setting('enabled_support_pixlr') == 'true'
6605
            ) {
6606
                return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
6607
            }
6608
6609
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
6610
        }
6611
6612
        if (in_array($path, self::get_system_folders())) {
6613
            return $iconDis;
6614
        }
6615
6616
        if ($isCertificateMode) {
6617
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id&curdirpath=/certificates");
6618
        }
6619
6620
        $sessionId = api_get_session_id();
6621
6622
        if ($sessionId && $documentData['session_id'] != $sessionId) {
6623
            return $iconDis;
6624
        }
6625
6626
        if (
6627
            $extension == 'svg' && api_browser_support('svg') &&
6628
            api_get_setting('enabled_support_svg') == 'true'
6629
        ) {
6630
            return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
6631
        }
6632
6633
        if (
6634
            in_array($extension, $webOdfExtensionList) &&
6635
            api_get_configuration_value('enabled_support_odf') === true
6636
        ) {
6637
            return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
6638
        }
6639
6640
        if (
6641
            in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6642
                api_get_setting('enabled_support_pixlr') == 'true'
6643
        ) {
6644
            return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
6645
        }
6646
6647
        return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
6648
    }
6649
6650
    /**
6651
     * Get the button to move document.
6652
     *
6653
     * @param bool  $isReadOnly
6654
     * @param array $documentData
6655
     * @param bool  $isCertificateMode
6656
     * @param int   $parentId
6657
     *
6658
     * @return string
6659
     */
6660
    private static function getButtonMove($isReadOnly, array $documentData, $isCertificateMode, $parentId)
6661
    {
6662
        $iconEn = Display::return_icon('move.png', get_lang('Move'));
6663
        $iconDis = Display::return_icon('move_na.png', get_lang('Move'));
6664
6665
        if ($isReadOnly) {
6666
            return $iconDis;
6667
        }
6668
6669
        $path = $documentData['path'];
6670
        $document_id = $documentData['id'];
6671
        $sessionId = api_get_session_id();
6672
        $courseParams = api_get_cidreq();
6673
6674
        if ($isCertificateMode || in_array($path, self::get_system_folders())) {
6675
            return $iconDis;
6676
        }
6677
6678
        if ($sessionId) {
6679
            if ($documentData['session_id'] != $sessionId) {
6680
                return $iconDis;
6681
            }
6682
        }
6683
6684
        $urlMoveParams = http_build_query(['id' => $parentId, 'move' => $document_id]);
6685
6686
        return Display::url(
6687
            $iconEn,
6688
            api_get_self()."?$courseParams&$urlMoveParams"
6689
        );
6690
    }
6691
6692
    /**
6693
     * Get the button to set visibility to document.
6694
     *
6695
     * @param bool  $isReadOnly
6696
     * @param int   $visibility
6697
     * @param array $documentData
6698
     * @param bool  $isCertificateMode
6699
     * @param int   $parentId
6700
     *
6701
     * @return null|string
6702
     */
6703
    private static function getButtonVisibility(
6704
        $isReadOnly,
6705
        $visibility,
6706
        array $documentData,
6707
        $isCertificateMode,
6708
        $parentId
6709
    ) {
6710
        $visibility_icon = $visibility == 0 ? 'invisible' : 'visible';
6711
        $visibility_command = $visibility == 0 ? 'set_visible' : 'set_invisible';
6712
        $courseParams = api_get_cidreq();
6713
6714
        if ($isReadOnly) {
6715
            if (api_is_allowed_to_edit() || api_is_platform_admin()) {
6716
                return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
6717
            }
6718
6719
            return null;
6720
        }
6721
6722
        if ($isCertificateMode) {
6723
            return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
6724
        }
6725
6726
        if (api_is_allowed_to_edit() || api_is_platform_admin()) {
6727
            $tip_visibility = $visibility_icon == 'invisible' ? get_lang('Show') : get_lang('Hide');
6728
6729
            return Display::url(
6730
                Display::return_icon($visibility_icon.'.png', $tip_visibility),
6731
                api_get_self()."?$courseParams&id=$parentId&$visibility_command={$documentData['id']}"
6732
            );
6733
        }
6734
6735
        return null;
6736
    }
6737
6738
    /**
6739
     * GEt the button to delete a document.
6740
     *
6741
     * @param bool   $isReadOnly
6742
     * @param array  $documentData
6743
     * @param bool   $isCertificateMode
6744
     * @param string $curDirPath
6745
     * @param int    $parentId
6746
     *
6747
     * @return string
6748
     */
6749
    private static function getButtonDelete(
6750
        $isReadOnly,
6751
        array $documentData,
6752
        $isCertificateMode,
6753
        $curDirPath,
6754
        $parentId
6755
    ) {
6756
        $iconEn = Display::return_icon('delete.png', get_lang('Delete'));
6757
        $iconDis = Display::return_icon('delete_na.png', get_lang('ThisFolderCannotBeDeleted'));
6758
        $path = $documentData['path'];
6759
        $id = $documentData['id'];
6760
        $courseParams = api_get_cidreq();
6761
6762
        if ($isReadOnly) {
6763
            return $iconDis;
6764
        }
6765
6766
        if (in_array($path, self::get_system_folders())) {
6767
            return $iconDis;
6768
        }
6769
6770
        $titleToShow = addslashes(basename($documentData['title']));
6771
        $urlDeleteParams = http_build_query([
6772
            'curdirpath' => $curDirPath,
6773
            'action' => 'delete_item',
6774
            'id' => $parentId,
6775
            'deleteid' => $documentData['id'],
6776
        ]);
6777
        $btn = Display::url(
6778
            $iconEn,
6779
            api_get_self()."?$courseParams&$urlDeleteParams",
6780
            ['onclick' => "return confirmation('$titleToShow');"]
6781
        );
6782
6783
        if (
6784
            isset($_GET['curdirpath']) &&
6785
            $_GET['curdirpath'] == '/certificates' &&
6786
            self::get_default_certificate_id(api_get_course_id()) == $id
6787
        ) {
6788
            return $btn;
6789
        }
6790
6791
        if ($isCertificateMode) {
6792
            return $btn;
6793
        }
6794
6795
        $sessionId = api_get_session_id();
6796
6797
        if ($sessionId) {
6798
            if ($documentData['session_id'] != $sessionId) {
6799
                return $iconDis;
6800
            }
6801
        }
6802
6803
        return $btn;
6804
    }
6805
}
6806