Completed
Push — master ( 38e61c...cd9a17 )
by Julito
14:03
created

DocumentManager::is_visible_by_id()   D

Complexity

Conditions 28
Paths 97

Size

Total Lines 138
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 28
eloc 71
nc 97
nop 6
dl 0
loc 138
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Resource\ResourceFile;
5
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
6
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
7
use Chamilo\CoreBundle\Framework\Container;
8
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
9
use Chamilo\CourseBundle\Entity\CDocument;
10
use Chamilo\CourseBundle\Entity\CGroupInfo;
11
use Chamilo\UserBundle\Entity\User;
12
use ChamiloSession as Session;
13
use Symfony\Component\HttpFoundation\File\UploadedFile;
14
15
/**
16
 *  Class DocumentManager
17
 *  This is the document library for Chamilo.
18
 *  It is / will be used to provide a service layer to all document-using tools.
19
 *  and eliminate code duplication fro group documents, scorm documents, main documents.
20
 *  Include/require it in your code to use its functionality.
21
 *
22
 * @package chamilo.library
23
 */
24
class DocumentManager
25
{
26
    /**
27
     * Construct.
28
     */
29
    private function __construct()
30
    {
31
    }
32
33
    /**
34
     * @param string $course_code
35
     *
36
     * @return int the document folder quota for the current course in bytes
37
     *             or the default quota
38
     */
39
    public static function get_course_quota($course_code = null)
40
    {
41
        if (empty($course_code)) {
42
            $course_info = api_get_course_info();
43
        } else {
44
            $course_info = api_get_course_info($course_code);
45
        }
46
47
        $course_quota = null;
48
        if (empty($course_info)) {
49
            return DEFAULT_DOCUMENT_QUOTA;
50
        } else {
51
            $course_quota = $course_info['disk_quota'];
52
        }
53
        if (is_null($course_quota) || empty($course_quota)) {
54
            // Course table entry for quota was null, then use default value
55
            $course_quota = DEFAULT_DOCUMENT_QUOTA;
56
        }
57
58
        return $course_quota;
59
    }
60
61
    /**
62
     * Get the content type of a file by checking the extension
63
     * We could use mime_content_type() with php-versions > 4.3,
64
     * but this doesn't work as it should on Windows installations.
65
     *
66
     * @param string $filename or boolean TRUE to return complete array
67
     *
68
     * @author ? first version
69
     * @author Bert Vanderkimpen
70
     *
71
     * @return string
72
     */
73
    public static function file_get_mime_type($filename)
74
    {
75
        // All MIME types in an array (from 1.6, this is the authorative source)
76
        // Please, keep this alphabetical if you add something to this list!
77
        $mimeTypes = [
78
            'ai' => 'application/postscript',
79
            'aif' => 'audio/x-aiff',
80
            'aifc' => 'audio/x-aiff',
81
            'aiff' => 'audio/x-aiff',
82
            'asf' => 'video/x-ms-asf',
83
            'asc' => 'text/plain',
84
            'au' => 'audio/basic',
85
            'avi' => 'video/x-msvideo',
86
            'bcpio' => 'application/x-bcpio',
87
            'bin' => 'application/octet-stream',
88
            'bmp' => 'image/bmp',
89
            'cdf' => 'application/x-netcdf',
90
            'class' => 'application/octet-stream',
91
            'cpio' => 'application/x-cpio',
92
            'cpt' => 'application/mac-compactpro',
93
            'csh' => 'application/x-csh',
94
            'css' => 'text/css',
95
            'dcr' => 'application/x-director',
96
            'dir' => 'application/x-director',
97
            'djv' => 'image/vnd.djvu',
98
            'djvu' => 'image/vnd.djvu',
99
            'dll' => 'application/octet-stream',
100
            'dmg' => 'application/x-diskcopy',
101
            'dms' => 'application/octet-stream',
102
            'doc' => 'application/msword',
103
            'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
104
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
105
            'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
106
            'dvi' => 'application/x-dvi',
107
            'dwg' => 'application/vnd.dwg',
108
            'dwf' => 'application/vnd.dwf',
109
            'dxf' => 'application/vnd.dxf',
110
            'dxr' => 'application/x-director',
111
            'eps' => 'application/postscript',
112
            'epub' => 'application/epub+zip',
113
            'etx' => 'text/x-setext',
114
            'exe' => 'application/octet-stream',
115
            'ez' => 'application/andrew-inset',
116
            'flv' => 'video/flv',
117
            'gif' => 'image/gif',
118
            'gtar' => 'application/x-gtar',
119
            'gz' => 'application/x-gzip',
120
            'hdf' => 'application/x-hdf',
121
            'hqx' => 'application/mac-binhex40',
122
            'htm' => 'text/html',
123
            'html' => 'text/html',
124
            'ice' => 'x-conference-xcooltalk',
125
            'ief' => 'image/ief',
126
            'iges' => 'model/iges',
127
            'igs' => 'model/iges',
128
            'jar' => 'application/java-archiver',
129
            'jpe' => 'image/jpeg',
130
            'jpeg' => 'image/jpeg',
131
            'jpg' => 'image/jpeg',
132
            'js' => 'application/x-javascript',
133
            'kar' => 'audio/midi',
134
            'lam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
135
            'latex' => 'application/x-latex',
136
            'lha' => 'application/octet-stream',
137
            'log' => 'text/plain',
138
            'lzh' => 'application/octet-stream',
139
            'm1a' => 'audio/mpeg',
140
            'm2a' => 'audio/mpeg',
141
            'm3u' => 'audio/x-mpegurl',
142
            'man' => 'application/x-troff-man',
143
            'me' => 'application/x-troff-me',
144
            'mesh' => 'model/mesh',
145
            'mid' => 'audio/midi',
146
            'midi' => 'audio/midi',
147
            'mov' => 'video/quicktime',
148
            'movie' => 'video/x-sgi-movie',
149
            'mp2' => 'audio/mpeg',
150
            'mp3' => 'audio/mpeg',
151
            'mp4' => 'video/mp4',
152
            'mpa' => 'audio/mpeg',
153
            'mpe' => 'video/mpeg',
154
            'mpeg' => 'video/mpeg',
155
            'mpg' => 'video/mpeg',
156
            'mpga' => 'audio/mpeg',
157
            'ms' => 'application/x-troff-ms',
158
            'msh' => 'model/mesh',
159
            'mxu' => 'video/vnd.mpegurl',
160
            'nc' => 'application/x-netcdf',
161
            'oda' => 'application/oda',
162
            'oga' => 'audio/ogg',
163
            'ogg' => 'application/ogg',
164
            'ogx' => 'application/ogg',
165
            'ogv' => 'video/ogg',
166
            'pbm' => 'image/x-portable-bitmap',
167
            'pct' => 'image/pict',
168
            'pdb' => 'chemical/x-pdb',
169
            'pdf' => 'application/pdf',
170
            'pgm' => 'image/x-portable-graymap',
171
            'pgn' => 'application/x-chess-pgn',
172
            'pict' => 'image/pict',
173
            'png' => 'image/png',
174
            'pnm' => 'image/x-portable-anymap',
175
            'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
176
            'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
177
            'pps' => 'application/vnd.ms-powerpoint',
178
            'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
179
            'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
180
            'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
181
            'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
182
            'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
183
            'ppm' => 'image/x-portable-pixmap',
184
            'ppt' => 'application/vnd.ms-powerpoint',
185
            'ps' => 'application/postscript',
186
            'qt' => 'video/quicktime',
187
            'ra' => 'audio/x-realaudio',
188
            'ram' => 'audio/x-pn-realaudio',
189
            'rar' => 'image/x-rar-compressed',
190
            'ras' => 'image/x-cmu-raster',
191
            'rgb' => 'image/x-rgb',
192
            'rm' => 'audio/x-pn-realaudio',
193
            'roff' => 'application/x-troff',
194
            'rpm' => 'audio/x-pn-realaudio-plugin',
195
            'rtf' => 'text/rtf',
196
            'rtx' => 'text/richtext',
197
            'sgm' => 'text/sgml',
198
            'sgml' => 'text/sgml',
199
            'sh' => 'application/x-sh',
200
            'shar' => 'application/x-shar',
201
            'silo' => 'model/mesh',
202
            'sib' => 'application/X-Sibelius-Score',
203
            'sit' => 'application/x-stuffit',
204
            'skd' => 'application/x-koan',
205
            'skm' => 'application/x-koan',
206
            'skp' => 'application/x-koan',
207
            'skt' => 'application/x-koan',
208
            'smi' => 'application/smil',
209
            'smil' => 'application/smil',
210
            'snd' => 'audio/basic',
211
            'so' => 'application/octet-stream',
212
            'spl' => 'application/x-futuresplash',
213
            'src' => 'application/x-wais-source',
214
            'sv4cpio' => 'application/x-sv4cpio',
215
            'sv4crc' => 'application/x-sv4crc',
216
            'svf' => 'application/vnd.svf',
217
            'svg' => 'image/svg+xml',
218
            //'svgz' => 'image/svg+xml',
219
            'swf' => 'application/x-shockwave-flash',
220
            'sxc' => 'application/vnd.sun.xml.calc',
221
            'sxi' => 'application/vnd.sun.xml.impress',
222
            'sxw' => 'application/vnd.sun.xml.writer',
223
            't' => 'application/x-troff',
224
            'tar' => 'application/x-tar',
225
            'tcl' => 'application/x-tcl',
226
            'tex' => 'application/x-tex',
227
            'texi' => 'application/x-texinfo',
228
            'texinfo' => 'application/x-texinfo',
229
            'tga' => 'image/x-targa',
230
            'tif' => 'image/tif',
231
            'tiff' => 'image/tiff',
232
            'tr' => 'application/x-troff',
233
            'tsv' => 'text/tab-seperated-values',
234
            'txt' => 'text/plain',
235
            'ustar' => 'application/x-ustar',
236
            'vcd' => 'application/x-cdlink',
237
            'vrml' => 'model/vrml',
238
            'wav' => 'audio/x-wav',
239
            'wbmp' => 'image/vnd.wap.wbmp',
240
            'wbxml' => 'application/vnd.wap.wbxml',
241
            'webp' => 'image/webp',
242
            'wml' => 'text/vnd.wap.wml',
243
            'wmlc' => 'application/vnd.wap.wmlc',
244
            'wmls' => 'text/vnd.wap.wmlscript',
245
            'wmlsc' => 'application/vnd.wap.wmlscriptc',
246
            'wma' => 'audio/x-ms-wma',
247
            'wmv' => 'video/x-ms-wmv',
248
            'wrl' => 'model/vrml',
249
            'xbm' => 'image/x-xbitmap',
250
            'xht' => 'application/xhtml+xml',
251
            'xhtml' => 'application/xhtml+xml',
252
            'xls' => 'application/vnd.ms-excel',
253
            'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
254
            'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
255
            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
256
            'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
257
            'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
258
            'xml' => 'text/xml',
259
            'xpm' => 'image/x-xpixmap',
260
            'xsl' => 'text/xml',
261
            'xwd' => 'image/x-windowdump',
262
            'xyz' => 'chemical/x-xyz',
263
            'zip' => 'application/zip',
264
        ];
265
266
        if ($filename === true) {
267
            return $mimeTypes;
268
        }
269
270
        // Get the extension of the file
271
        $extension = explode('.', $filename);
272
273
        // $filename will be an array if a . was found
274
        if (is_array($extension)) {
275
            $extension = strtolower($extension[count($extension) - 1]);
276
        } else {
277
            //file without extension
278
            $extension = 'empty';
279
        }
280
281
        //if the extension is found, return the content type
282
        if (isset($mimeTypes[$extension])) {
283
            return $mimeTypes[$extension];
284
        }
285
286
        return 'application/octet-stream';
287
    }
288
289
    /**
290
     * This function smart streams a file to the client using HTTP headers.
291
     *
292
     * @param string $fullFilename The full path of the file to be sent
293
     * @param string $filename     The name of the file as shown to the client
294
     * @param string $contentType  The MIME type of the file
295
     *
296
     * @return bool false if file doesn't exist, true if stream succeeded
297
     */
298
    public static function smartReadFile($fullFilename, $filename, $contentType = 'application/octet-stream')
299
    {
300
        if (!file_exists($fullFilename)) {
301
            header("HTTP/1.1 404 Not Found");
302
303
            return false;
304
        }
305
306
        $size = filesize($fullFilename);
307
        $time = date('r', filemtime($fullFilename));
308
309
        $fm = @fopen($fullFilename, 'rb');
310
        if (!$fm) {
0 ignored issues
show
introduced by
$fm is of type false|resource, thus it always evaluated to false.
Loading history...
311
            header("HTTP/1.1 505 Internal server error");
312
313
            return false;
314
        }
315
316
        $begin = 0;
317
        $end = $size - 1;
318
319
        if (isset($_SERVER['HTTP_RANGE'])) {
320
            if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
321
                $begin = intval($matches[1]);
322
                if (!empty($matches[2])) {
323
                    $end = intval($matches[2]);
324
                }
325
            }
326
        }
327
328
        if (isset($_SERVER['HTTP_RANGE'])) {
329
            header('HTTP/1.1 206 Partial Content');
330
        } else {
331
            header('HTTP/1.1 200 OK');
332
        }
333
334
        header("Content-Type: $contentType");
335
        header('Cache-Control: public, must-revalidate, max-age=0');
336
        header('Pragma: no-cache');
337
        header('Accept-Ranges: bytes');
338
        header('Content-Length:'.(($end - $begin) + 1));
339
        if (isset($_SERVER['HTTP_RANGE'])) {
340
            header("Content-Range: bytes $begin-$end/$size");
341
        }
342
        header("Content-Disposition: inline; filename=$filename");
343
        header("Content-Transfer-Encoding: binary");
344
        header("Last-Modified: $time");
345
346
        $cur = $begin;
347
        fseek($fm, $begin, 0);
348
349
        while (!feof($fm) && $cur <= $end && (connection_status() == 0)) {
350
            echo fread($fm, min(1024 * 16, ($end - $cur) + 1));
351
            $cur += 1024 * 16;
352
        }
353
    }
354
355
    /**
356
     * This function streams a file to the client.
357
     *
358
     * @param string $full_file_name
359
     * @param bool   $forced
360
     * @param string $name
361
     * @param bool   $fixLinksHttpToHttps change file content from http to https
362
     *
363
     * @return false if file doesn't exist, true if stream succeeded
364
     */
365
    public static function file_send_for_download(
366
        $full_file_name,
367
        $forced = false,
368
        $name = '',
369
        $fixLinksHttpToHttps = false
370
    ) {
371
        session_write_close(); //we do not need write access to session anymore
372
        if (!is_file($full_file_name)) {
373
            return false;
374
        }
375
        $filename = $name == '' ? basename($full_file_name) : api_replace_dangerous_char($name);
376
        $len = filesize($full_file_name);
377
        // Fixing error when file name contains a ","
378
        $filename = str_replace(',', '', $filename);
379
        $sendFileHeaders = api_get_configuration_value('enable_x_sendfile_headers');
380
381
        // Allows chrome to make videos and audios seekable
382
        header('Accept-Ranges: bytes');
383
384
        if ($forced) {
385
            // Force the browser to save the file instead of opening it
386
            if (isset($sendFileHeaders) &&
387
                !empty($sendFileHeaders)) {
388
                header("X-Sendfile: $filename");
389
            }
390
391
            header('Content-type: application/octet-stream');
392
            header('Content-length: '.$len);
393
            if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
394
                header('Content-Disposition: filename= '.$filename);
395
            } else {
396
                header('Content-Disposition: attachment; filename= '.$filename);
397
            }
398
            if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
399
                header('Pragma: ');
400
                header('Cache-Control: ');
401
                header('Cache-Control: public'); // IE cannot download from sessions without a cache
402
            }
403
            header('Content-Description: '.$filename);
404
            header('Content-Transfer-Encoding: binary');
405
406
            if (function_exists('ob_end_clean') && ob_get_length()) {
407
                // Use ob_end_clean() to avoid weird buffering situations
408
                // where file is sent broken/incomplete for download
409
                ob_end_clean();
410
            }
411
412
            $res = fopen($full_file_name, 'r');
413
            fpassthru($res);
414
415
            return true;
416
        } else {
417
            // no forced download, just let the browser decide what to do according to the mimetype
418
            $lpFixedEncoding = api_get_setting('lp.fixed_encoding') === 'true';
419
420
            // Commented to let courses content to be cached in order to improve performance:
421
            //header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
422
            //header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
423
424
            // Commented to avoid double caching declaration when playing with IE and HTTPS
425
            //header('Cache-Control: no-cache, must-revalidate');
426
            //header('Pragma: no-cache');
427
428
            $contentType = self::file_get_mime_type($filename);
429
430
            switch ($contentType) {
431
                case 'text/html':
432
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
433
                        $contentType .= '; charset=UTF-8';
434
                    } else {
435
                        $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
436
                        if (!empty($encoding)) {
437
                            $contentType .= '; charset='.$encoding;
438
                        }
439
                    }
440
                    break;
441
                case 'text/plain':
442
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
443
                        $contentType .= '; charset=UTF-8';
444
                    } else {
445
                        $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
446
                        if (!empty($encoding)) {
447
                            $contentType .= '; charset='.$encoding;
448
                        }
449
                    }
450
                    break;
451
                case 'video/mp4':
452
                case 'audio/mpeg':
453
                case 'audio/mp4':
454
                case 'audio/ogg':
455
                case 'audio/webm':
456
                case 'audio/wav':
457
                case 'video/ogg':
458
                case 'video/webm':
459
                    self::smartReadFile($full_file_name, $filename, $contentType);
460
                    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...
461
                case 'application/vnd.dwg':
462
                case 'application/vnd.dwf':
463
                    header('Content-type: application/octet-stream');
464
                    break;
465
            }
466
467
            header('Content-type: '.$contentType);
468
            header('Content-Length: '.$len);
469
            $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);
470
471
            if (strpos($userAgent, 'msie')) {
472
                header('Content-Disposition: ; filename= '.$filename);
473
            } else {
474
                //header('Content-Disposition: inline');
475
                header('Content-Disposition: inline;');
476
            }
477
478
            if ($fixLinksHttpToHttps) {
479
                $content = file_get_contents($full_file_name);
480
                $content = str_replace(
481
                    ['http%3A%2F%2F', 'http://'],
482
                    ['https%3A%2F%2F', 'https://'],
483
                    $content
484
                );
485
                echo $content;
486
            } else {
487
                if (function_exists('ob_end_clean') && ob_get_length()) {
488
                    // Use ob_end_clean() to avoid weird buffering situations
489
                    // where file is sent broken/incomplete for download
490
                    ob_end_clean();
491
                }
492
493
                readfile($full_file_name);
494
            }
495
496
            return true;
497
        }
498
    }
499
500
    /**
501
     * Session folder filters.
502
     *
503
     * @param string $path
504
     * @param int    $sessionId
505
     *
506
     * @return string|null
507
     */
508
    public static function getSessionFolderFilters($path, $sessionId)
509
    {
510
        $sessionId = (int) $sessionId;
511
        $condition = null;
512
513
        if (!empty($sessionId)) {
514
            // Chat folder filter
515
            if ($path == '/chat_files') {
516
                $condition .= " AND (docs.session_id = '$sessionId') ";
517
            }
518
            // share_folder filter
519
            $condition .= " AND docs.path != '/shared_folder' ";
520
        }
521
522
        return $condition;
523
    }
524
525
    /**
526
     * Fetches all document data for the given user/group.
527
     *
528
     * @param array     $courseInfo
529
     * @param string    $path
530
     * @param int       $toGroupId       iid
531
     * @param int       $toUserId
532
     * @param bool      $canSeeInvisible
533
     * @param bool      $search
534
     * @param int       $sessionId
535
     * @param User|null $currentUser
536
     *
537
     * @return array with all document data
538
     */
539
    public static function getAllDocumentData(
540
        $courseInfo,
541
        $path = '/',
542
        $toGroupId = 0,
543
        $toUserId = null,
544
        $canSeeInvisible = false,
545
        $search = false,
546
        $sessionId = 0,
547
        User $currentUser = null
548
    ) {
549
        if (empty($courseInfo)) {
550
            return [];
551
        }
552
553
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
554
        $currentUser = $currentUser ?: api_get_current_user();
555
556
        $userGroupFilter = '';
557
        if (!is_null($toUserId)) {
558
            $toUserId = (int) $toUserId;
559
            $userGroupFilter = "last.to_user_id = $toUserId";
560
            if (empty($toUserId)) {
561
                $userGroupFilter = ' (last.to_user_id = 0 OR last.to_user_id IS NULL) ';
562
            }
563
        } else {
564
            $toGroupId = (int) $toGroupId;
565
            $userGroupFilter = "last.to_group_id = $toGroupId";
566
            if (empty($toGroupId)) {
567
                $userGroupFilter = '( last.to_group_id = 0 OR last.to_group_id IS NULL) ';
568
            }
569
        }
570
571
        // Escape underscores in the path so they don't act as a wildcard
572
        $originalPath = $path;
573
        $path = str_replace('_', '\_', $path);
574
575
        $visibilityBit = ' <> 2';
576
577
        // The given path will not end with a slash, unless it's the root '/'
578
        // so no root -> add slash
579
        $addedSlash = $path == '/' ? '' : '/';
580
581
        // Condition for the session
582
        $sessionId = $sessionId ?: api_get_session_id();
583
        $conditionSession = " AND (last.session_id = '$sessionId' OR (last.session_id = '0' OR last.session_id IS NULL) )";
584
        $conditionSession .= self::getSessionFolderFilters($originalPath, $sessionId);
585
586
        $sharedCondition = null;
587
        if ($originalPath == '/shared_folder') {
588
            $students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
589
            if (!empty($students)) {
590
                $conditionList = [];
591
                foreach ($students as $studentInfo) {
592
                    $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
593
                }
594
                $sharedCondition .= ' AND docs.path IN ("'.implode('","', $conditionList).'")';
595
            }
596
        }
597
598
        $sql = "SELECT
599
                    docs.id,
600
                    docs.filetype,
601
                    docs.path,
602
                    docs.title,
603
                    docs.comment,
604
                    docs.size,
605
                    docs.readonly,
606
                    docs.session_id,
607
                    creator_id,
608
                    visibility,
609
                    n.updated_at,
610
                    n.created_at,
611
                    n.creator_id                                     
612
                FROM resource_node AS n
613
                INNER JOIN $tblDocument AS docs
614
                ON (docs.resource_node_id = n.id)
615
                INNER JOIN resource_link l
616
                ON (l.resource_node_id = n.id)                
617
                WHERE
618
                    docs.c_id = {$courseInfo['real_id']} AND                    
619
                    docs.path LIKE '".Database::escape_string($path.$addedSlash.'%')."' AND
620
                    docs.path NOT LIKE '".Database::escape_string($path.$addedSlash.'%/%')."' AND
621
                    docs.path NOT LIKE '%_DELETED_%' AND
622
                    l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')
623
                    $sharedCondition               
624
                ";
625
        //$userGroupFilter AND
626
        //$conditionSession
627
        $result = Database::query($sql);
628
629
        $documentData = [];
630
        $isAllowedToEdit = api_is_allowed_to_edit(null, true);
631
        $isCoach = api_is_coach();
632
        if ($result !== false && Database::num_rows($result) != 0) {
633
            $rows = [];
634
635
            $hideInvisibleDocuments = api_get_configuration_value('hide_invisible_course_documents_in_sessions');
636
637
            while ($row = Database::fetch_array($result, 'ASSOC')) {
638
                if (isset($rows[$row['id']])) {
639
                    continue;
640
                }
641
642
                // If we are in session and hide_invisible_course_documents_in_sessions is enabled
643
                // Then we avoid the documents that have visibility in session but that they come from a base course
644
                if ($hideInvisibleDocuments && $sessionId) {
645
                    if ($row['item_property_session_id'] == $sessionId && empty($row['session_id'])) {
646
                        continue;
647
                    }
648
                }
649
650
                if (self::isBasicCourseFolder($row['path'], $sessionId)) {
651
                    $basicCourseDocumentsContent = self::getAllDocumentData(
652
                        $courseInfo,
653
                        $row['path']
654
                    );
655
656
                    if (empty($basicCourseDocumentsContent)) {
657
                        continue;
658
                    }
659
                }
660
661
                $rows[$row['id']] = $row;
662
            }
663
664
            // If we are in session and hide_invisible_course_documents_in_sessions is enabled
665
            // Or if we are students
666
            // Then don't list the invisible or deleted documents
667
            if (($sessionId && $hideInvisibleDocuments) || (!$isCoach && !$isAllowedToEdit)) {
668
                $rows = array_filter($rows, function ($row) {
669
                    if (in_array(
670
                        $row['visibility'],
671
                        [
672
                            ResourceLink::VISIBILITY_DELETED,
673
                            ResourceLink::VISIBILITY_DRAFT,
674
                        ]
675
                    )) {
676
                        return false;
677
                    }
678
679
                    return true;
680
                });
681
            }
682
683
            foreach ($rows as $row) {
684
                if ($row['filetype'] == 'file' &&
685
                    pathinfo($row['path'], PATHINFO_EXTENSION) == 'html'
686
                ) {
687
                    // Templates management
688
                    $tblTemplate = Database::get_main_table(TABLE_MAIN_TEMPLATES);
689
                    $sql = "SELECT id FROM $tblTemplate
690
                            WHERE
691
                                c_id = '".$courseInfo['real_id']."' AND
692
                                user_id = '".$currentUser->getId()."' AND
693
                                ref_doc = '".$row['id']."'";
694
                    $templateResult = Database::query($sql);
695
                    $row['is_template'] = (Database::num_rows($templateResult) > 0) ? 1 : 0;
696
                }
697
                $row['basename'] = basename($row['path']);
698
                // Just filling $document_data.
699
                $documentData[$row['id']] = $row;
700
            }
701
702
            // Only for the student we filter the results see BT#1652
703
            if (!$isCoach && !$isAllowedToEdit) {
704
                // Checking parents visibility.
705
                $finalDocumentData = [];
706
                foreach ($documentData as $row) {
707
                    $isVisible = self::check_visibility_tree(
708
                        $row['id'],
709
                        $courseInfo,
710
                        $sessionId,
711
                        $currentUser->getId(),
712
                        $toGroupId
713
                    );
714
                    if ($isVisible) {
715
                        $finalDocumentData[$row['id']] = $row;
716
                    }
717
                }
718
            } else {
719
                $finalDocumentData = $documentData;
720
            }
721
722
            return $finalDocumentData;
723
        } else {
724
            return [];
725
        }
726
    }
727
728
    /**
729
     * Gets the paths of all folders in a course
730
     * can show all folders (except for the deleted ones) or only visible ones.
731
     *
732
     * @param array  $courseInfo
733
     * @param int    $groupIid          iid
734
     * @param bool   $can_see_invisible
735
     * @param bool   $getInvisibleList
736
     * @param string $path              current path
737
     *
738
     * @return array with paths
739
     */
740
    public static function get_all_document_folders(
741
        $courseInfo,
742
        $groupIid = 0,
743
        $can_see_invisible = false,
744
        $getInvisibleList = false,
745
        $path = ''
746
    ) {
747
        if (empty($courseInfo)) {
748
            return [];
749
        }
750
751
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
752
        $groupIid = (int) $groupIid;
753
        $courseId = $courseInfo['real_id'];
754
        $sessionId = api_get_session_id();
755
756
        $folders = [];
757
        $students = CourseManager::get_user_list_from_course_code(
758
            $courseInfo['code'],
759
            api_get_session_id()
760
        );
761
762
        $conditionList = [];
763
        if (!empty($students)) {
764
            foreach ($students as $studentId => $studentInfo) {
765
                $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
766
            }
767
        }
768
769
        $groupCondition = " l.group_id = $groupIid";
770
        if (empty($groupIid)) {
771
            $groupCondition = ' (l.group_id = 0 OR l.group_id IS NULL)';
772
        }
773
774
        $show_users_condition = '';
775
        if (api_get_setting('show_users_folders') === 'false') {
776
            $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
777
        }
778
779
        if ($can_see_invisible) {
780
            $sessionId = $sessionId ?: api_get_session_id();
781
            $condition_session = " AND (l.session_id = '$sessionId' OR (l.session_id = '0' OR l.session_id IS NULL) )";
782
            $condition_session .= self::getSessionFolderFilters($path, $sessionId);
783
784
            $sql = "SELECT DISTINCT docs.id, docs.path
785
                    FROM resource_node AS n
786
                    INNER JOIN $TABLE_DOCUMENT  AS docs
787
                    ON (docs.resource_node_id = n.id)
788
                    INNER JOIN resource_link l
789
                    ON (l.resource_node_id = n.id)
790
                    WHERE                      
791
                        docs.c_id = $courseId AND
792
                        docs.filetype = 'folder' AND
793
                        $groupCondition AND
794
                        docs.path NOT LIKE '%shared_folder%' AND
795
                        docs.path NOT LIKE '%_DELETED_%' AND
796
                        l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')                           
797
                        $condition_session ";
798
799
            if ($groupIid != 0) {
800
                $sql .= " AND docs.path NOT LIKE '%shared_folder%' ";
801
            } else {
802
                $sql .= $show_users_condition;
803
            }
804
805
            $result = Database::query($sql);
806
            if ($result && Database::num_rows($result) != 0) {
807
                while ($row = Database::fetch_array($result, 'ASSOC')) {
808
                    if (self::is_folder_to_avoid($row['path'])) {
809
                        continue;
810
                    }
811
812
                    if (strpos($row['path'], '/shared_folder/') !== false) {
813
                        if (!in_array($row['path'], $conditionList)) {
814
                            continue;
815
                        }
816
                    }
817
818
                    $folders[$row['id']] = $row['path'];
819
                }
820
821
                if (!empty($folders)) {
822
                    natsort($folders);
823
                }
824
825
                return $folders;
826
            } else {
827
                return false;
828
            }
829
        } else {
830
            // No invisible folders
831
            // Condition for the session
832
            $condition_session = api_get_session_condition(
833
                $sessionId,
834
                true,
835
                false,
836
                'docs.session_id'
837
            );
838
839
            $visibilityCondition = 'l.visibility = 1';
840
            $fileType = "docs.filetype = 'folder' AND";
841
            if ($getInvisibleList) {
842
                $visibilityCondition = 'l.visibility = 0';
843
                $fileType = '';
844
            }
845
846
            //get visible folders
847
            $sql = "SELECT DISTINCT docs.id, docs.path
848
                    FROM resource_node AS n
849
                    INNER JOIN $TABLE_DOCUMENT  AS docs
850
                    ON (docs.resource_node_id = n.id)
851
                    INNER JOIN resource_link l
852
                    ON (l.resource_node_id = n.id)
853
                    WHERE
854
                        $fileType                        
855
                        $groupCondition AND
856
                        $visibilityCondition
857
                        $show_users_condition
858
                        $condition_session AND                        
859
                        docs.c_id = $courseId ";
860
            $result = Database::query($sql);
861
            $visibleFolders = [];
862
            while ($row = Database::fetch_array($result, 'ASSOC')) {
863
                $visibleFolders[$row['id']] = $row['path'];
864
            }
865
866
            if ($getInvisibleList) {
867
                return $visibleFolders;
868
            }
869
870
            // get invisible folders
871
            $sql = "SELECT DISTINCT docs.id, docs.path
872
                    FROM resource_node AS n
873
                    INNER JOIN $TABLE_DOCUMENT  AS docs
874
                    ON (docs.resource_node_id = n.id)
875
                    INNER JOIN resource_link l
876
                    ON (l.resource_node_id = n.id)
877
                    WHERE                        
878
                        docs.filetype = 'folder' AND                        
879
                        $groupCondition AND                        
880
                        l.visibility IN ('".ResourceLink::VISIBILITY_PENDING."') 
881
                        $condition_session AND                        
882
                        docs.c_id = $courseId ";
883
            $result = Database::query($sql);
884
            $invisibleFolders = [];
885
            while ($row = Database::fetch_array($result, 'ASSOC')) {
886
                //get visible folders in the invisible ones -> they are invisible too
887
                $sql = "SELECT DISTINCT docs.id, docs.path
888
                        FROM resource_node AS n
889
                        INNER JOIN $TABLE_DOCUMENT  AS docs
890
                        ON (docs.resource_node_id = n.id)
891
                        INNER JOIN resource_link l
892
                        ON (l.resource_node_id = n.id)
893
                        WHERE                            
894
                            docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
895
                            docs.filetype = 'folder' AND                            
896
                            $groupCondition AND
897
                            l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."') 
898
                            $condition_session AND                            
899
                            docs.c_id = $courseId ";
900
                $folder_in_invisible_result = Database::query($sql);
901
                while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
902
                    $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
903
                }
904
            }
905
906
            // If both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
907
            if (is_array($visibleFolders) && is_array($invisibleFolders)) {
908
                $folders = array_diff($visibleFolders, $invisibleFolders);
909
                natsort($folders);
910
911
                return $folders;
912
            }
913
914
            if (is_array($visibleFolders)) {
915
                natsort($visibleFolders);
916
917
                return $visibleFolders;
918
            }
919
920
            // no visible folders found
921
            return false;
922
        }
923
    }
924
925
    /**
926
     * This check if a document has the readonly property checked, then see if the user
927
     * is the owner of this file, if all this is true then return true.
928
     *
929
     * @param array  $_course
930
     * @param int    $user_id     id of the current user
931
     * @param string $file        path stored in the database (if not defined, $documentId must be used)
932
     * @param int    $document_id in case you don't have the file path ,
933
     *                            insert the id of the file here and leave $file in blank ''
934
     * @param bool   $to_delete
935
     * @param int    $sessionId
936
     *
937
     * @return bool true/false
938
     * */
939
    public static function check_readonly(
940
        $_course,
941
        $user_id,
942
        $file = null,
943
        $document_id = 0,
944
        $to_delete = false,
945
        $sessionId = null
946
    ) {
947
        $sessionId = (int) $sessionId;
948
        if (empty($sessionId)) {
949
            $sessionId = api_get_session_id();
950
        }
951
        $document_id = (int) $document_id;
952
        if (empty($document_id)) {
953
            $document_id = self::get_document_id($_course, $file, $sessionId);
954
        }
955
956
        $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
957
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
958
        $course_id = $_course['real_id'];
959
960
        if ($to_delete) {
961
            if (self::isFolder($_course, $document_id)) {
962
                if (!empty($file)) {
963
                    $path = Database::escape_string($file);
964
                    // Check
965
                    $sql = "SELECT td.id, readonly, tp.insert_user_id
966
                            FROM $TABLE_DOCUMENT td 
967
                            INNER JOIN $TABLE_PROPERTY tp
968
                            ON (td.c_id = tp.c_id AND tp.ref= td.id)
969
                            WHERE
970
                                td.c_id = $course_id AND
971
                                tp.c_id = $course_id AND
972
                                td.session_id = $sessionId AND                                
973
                                (path='".$path."' OR path LIKE BINARY '".$path."/%' ) ";
974
                    // Get all id's of documents that are deleted
975
                    $what_to_check_result = Database::query($sql);
976
977
                    if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
978
                        // file with readonly set to 1 exist?
979
                        $readonly_set = false;
980
                        while ($row = Database::fetch_array($what_to_check_result)) {
981
                            //query to delete from item_property table
982
                            if ($row['readonly'] == 1) {
983
                                if (!($row['insert_user_id'] == $user_id)) {
984
                                    $readonly_set = true;
985
                                    break;
986
                                }
987
                            }
988
                        }
989
990
                        if ($readonly_set) {
991
                            return true;
992
                        }
993
                    }
994
                }
995
996
                return false;
997
            }
998
        }
999
1000
        if (!empty($document_id)) {
1001
            $sql = "SELECT a.insert_user_id, b.readonly
1002
                   FROM $TABLE_PROPERTY a 
1003
                   INNER JOIN $TABLE_DOCUMENT b
1004
                   ON (a.c_id = b.c_id AND a.ref= b.id)
1005
                   WHERE
1006
            			a.c_id = $course_id AND
1007
                        b.c_id = $course_id AND
1008
            			a.ref = $document_id 
1009
                    LIMIT 1";
1010
            $result = Database::query($sql);
1011
            $doc_details = Database::fetch_array($result, 'ASSOC');
1012
1013
            if ($doc_details['readonly'] == 1) {
1014
                return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
1015
            }
1016
        }
1017
1018
        return false;
1019
    }
1020
1021
    /**
1022
     * This check if a document is a folder or not.
1023
     *
1024
     * @param array $_course
1025
     * @param int   $id      document id
1026
     *
1027
     * @return bool true/false
1028
     * */
1029
    public static function isFolder($_course, $id)
1030
    {
1031
        $table = Database::get_course_table(TABLE_DOCUMENT);
1032
        if (empty($_course)) {
1033
            return false;
1034
        }
1035
        $course_id = $_course['real_id'];
1036
        $id = (int) $id;
1037
        $sql = "SELECT filetype FROM $table
1038
                WHERE c_id = $course_id AND id= $id";
1039
        $result = Database::fetch_array(Database::query($sql), 'ASSOC');
1040
1041
        return $result['filetype'] === 'folder';
1042
    }
1043
1044
    /**
1045
     * @param int   $document_id
1046
     * @param array $course_info
1047
     * @param int   $session_id
1048
     * @param bool  $remove_content_from_db
1049
     */
1050
    public static function deleteDocumentFromDb(
1051
        $document_id,
1052
        $course_info = [],
1053
        $session_id = 0,
1054
        $remove_content_from_db = false
1055
    ) {
1056
        // Deleting from the DB
1057
        $user_id = api_get_user_id();
1058
        $document_id = intval($document_id);
1059
1060
        if (empty($course_info)) {
1061
            $course_info = api_get_course_info();
1062
        }
1063
1064
        if (empty($session_id)) {
1065
            $session_id = api_get_session_id();
1066
        }
1067
        // Soft DB delete
1068
        /*api_item_property_update(
1069
            $course_info,
1070
            TOOL_DOCUMENT,
1071
            $document_id,
1072
            'delete',
1073
            $user_id,
1074
            null,
1075
            null,
1076
            null,
1077
            null,
1078
            $session_id
1079
        );*/
1080
        self::delete_document_from_search_engine($course_info['code'], $document_id);
1081
        self::unsetDocumentAsTemplate($document_id, $course_info['real_id'], $user_id);
1082
1083
        // Hard DB delete
1084
        if ($remove_content_from_db) {
1085
            $repo = Container::getDocumentRepository();
1086
            /** @var CDocument $document */
1087
            $document = $repo->find($document_id);
1088
            $repo->softDelete($document);
1089
1090
            return true;
1091
1092
            /*$sql = "DELETE FROM $TABLE_ITEMPROPERTY
1093
                    WHERE
1094
                        c_id = {$course_info['real_id']} AND
1095
                        ref = ".$document_id." AND
1096
                        tool='".TOOL_DOCUMENT."'";
1097
            Database::query($sql);
1098
1099
            $sql = "DELETE FROM $TABLE_DOCUMENT
1100
                    WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
1101
            Database::query($sql);*/
1102
        }
1103
    }
1104
1105
    /**
1106
     * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
1107
     * Files/folders that are inside a deleted folder get visibility 2.
1108
     *
1109
     * @param array  $_course
1110
     * @param string $path          Path stored in the database
1111
     * @param string $base_work_dir Path to the documents folder (if not defined, $documentId must be used)
1112
     * @param int    $sessionId     The ID of the session, if any
1113
     * @param int    $documentId    The document id, if available
1114
     * @param int    $groupId       iid
1115
     *
1116
     * @return bool true/false
1117
     *
1118
     * @todo now only files/folders in a folder get visibility 2, we should rename them too.
1119
     * @todo We should be able to get rid of this later when using only documentId (check further usage)
1120
     */
1121
    public static function delete_document(
1122
        $_course,
1123
        $path = null,
1124
        $base_work_dir = null,
1125
        $sessionId = null,
1126
        $documentId = null,
1127
        $groupId = 0
1128
    ) {
1129
        $groupId = (int) $groupId;
1130
        if (empty($groupId)) {
1131
            $groupId = api_get_group_id();
1132
        }
1133
1134
        $sessionId = (int) $sessionId;
1135
        if (empty($sessionId)) {
1136
            $sessionId = api_get_session_id();
1137
        }
1138
1139
        $course_id = $_course['real_id'];
1140
1141
        if (empty($course_id)) {
1142
            return false;
1143
        }
1144
1145
        if (empty($documentId)) {
1146
            $documentId = self::get_document_id($_course, $path, $sessionId);
1147
            $docInfo = self::get_document_data_by_id(
1148
                $documentId,
1149
                $_course['code'],
1150
                false,
1151
                $sessionId
1152
            );
1153
            $path = $docInfo['path'];
1154
        } else {
1155
            $docInfo = self::get_document_data_by_id(
1156
                $documentId,
1157
                $_course['code'],
1158
                false,
1159
                $sessionId
1160
            );
1161
            if (empty($docInfo)) {
1162
                return false;
1163
            }
1164
            $path = $docInfo['path'];
1165
        }
1166
1167
        $documentId = (int) $documentId;
1168
1169
        if (empty($path) || empty($docInfo) || empty($documentId)) {
1170
            return false;
1171
        }
1172
1173
        $repo = Container::getDocumentRepository();
1174
        /** @var CDocument $document */
1175
        $document = $repo->find($docInfo['iid']);
1176
        $repo->softDelete($document);
1177
1178
        return true;
1179
    }
1180
1181
    /**
1182
     * Removes documents from search engine database.
1183
     *
1184
     * @param string $course_id   Course code
1185
     * @param int    $document_id Document id to delete
1186
     */
1187
    public static function delete_document_from_search_engine($course_id, $document_id)
1188
    {
1189
        // remove from search engine if enabled
1190
        if (api_get_setting('search_enabled') === 'true') {
1191
            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
1192
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1193
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1194
            $res = Database::query($sql);
1195
            if (Database::num_rows($res) > 0) {
1196
                $row2 = Database::fetch_array($res);
1197
                $di = new ChamiloIndexer();
1198
                $di->remove_document($row2['search_did']);
1199
            }
1200
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1201
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1202
            Database::query($sql);
1203
1204
            // remove terms from db
1205
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1206
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $document_id);
1207
        }
1208
    }
1209
1210
    /**
1211
     * Gets the id of a document with a given path.
1212
     *
1213
     * @param array  $courseInfo
1214
     * @param string $path
1215
     * @param int    $sessionId
1216
     *
1217
     * @return int id of document / false if no doc found
1218
     */
1219
    public static function get_document_id($courseInfo, $path, $sessionId = 0)
1220
    {
1221
        $table = Database::get_course_table(TABLE_DOCUMENT);
1222
        $courseId = $courseInfo['real_id'];
1223
1224
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
1225
        $sessionCondition = api_get_session_condition($sessionId, true);
1226
1227
        $path = Database::escape_string($path);
1228
        if (!empty($courseId) && !empty($path)) {
1229
            $sql = "SELECT id FROM $table
1230
                    WHERE
1231
                        c_id = $courseId AND
1232
                        path LIKE BINARY '$path'
1233
                        $sessionCondition
1234
                    LIMIT 1";
1235
1236
            $result = Database::query($sql);
1237
            if (Database::num_rows($result)) {
1238
                $row = Database::fetch_array($result);
1239
1240
                return (int) $row['id'];
1241
            }
1242
        }
1243
1244
        return false;
1245
    }
1246
1247
    /**
1248
     * Gets the document data with a given id.
1249
     *
1250
     * @param int    $id            Document Id (id field in c_document table)
1251
     * @param string $course_code   Course code
1252
     * @param bool   $load_parents  load folder parents
1253
     * @param int    $session_id    The session ID,
1254
     *                              0 if requires context *out of* session, and null to use global context
1255
     * @param bool   $ignoreDeleted
1256
     *
1257
     * @return array document content
1258
     */
1259
    public static function get_document_data_by_id(
1260
        $id,
1261
        $course_code,
1262
        $load_parents = false,
1263
        $session_id = null,
1264
        $ignoreDeleted = false
1265
    ) {
1266
        $course_info = api_get_course_info($course_code);
1267
        $course_id = $course_info['real_id'];
1268
1269
        if (empty($course_info)) {
1270
            return false;
1271
        }
1272
1273
        $session_id = empty($session_id) ? api_get_session_id() : (int) $session_id;
1274
        $groupId = api_get_group_id();
1275
1276
        $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
1277
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1278
        $id = (int) $id;
1279
        $sessionCondition = api_get_session_condition($session_id, true, true);
1280
1281
        $sql = "SELECT * FROM $TABLE_DOCUMENT
1282
                WHERE c_id = $course_id $sessionCondition AND id = $id";
1283
1284
        if ($ignoreDeleted) {
1285
            $sql .= " AND path NOT LIKE '%_DELETED_%' ";
1286
        }
1287
1288
        $result = Database::query($sql);
1289
        $courseParam = '&cidReq='.$course_code.'&id='.$id.'&id_session='.$session_id.'&gidReq='.$groupId;
1290
        if ($result && Database::num_rows($result) == 1) {
1291
            $row = Database::fetch_array($result, 'ASSOC');
1292
            //@todo need to clarify the name of the URLs not nice right now
1293
            $url_path = urlencode($row['path']);
1294
            $path = str_replace('%2F', '/', $url_path);
1295
            $pathinfo = pathinfo($row['path']);
1296
1297
            $row['url'] = api_get_path(WEB_CODE_PATH).'document/showinframes.php?id='.$id.$courseParam;
1298
            $row['document_url'] = api_get_path(WEB_CODE_PATH).'document/document.php?id='.$id.$courseParam;
1299
            $row['absolute_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
1300
            $row['absolute_path_from_document'] = '/document'.$row['path'];
1301
            $row['absolute_parent_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$pathinfo['dirname'].'/';
1302
            $row['direct_url'] = $www.$path;
1303
            $row['basename'] = basename($row['path']);
1304
1305
            if (dirname($row['path']) == '.') {
1306
                $row['parent_id'] = '0';
1307
            } else {
1308
                $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), $session_id);
1309
                if (empty($row['parent_id'])) {
1310
                    // Try one more with session id = 0
1311
                    $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), 0);
1312
                }
1313
            }
1314
            $parents = [];
1315
1316
            //Use to generate parents (needed for the breadcrumb)
1317
            //@todo sorry but this for is here because there's not a parent_id in the document table so we parsed the path!!
1318
            if ($load_parents) {
1319
                $dir_array = explode('/', $row['path']);
1320
                $dir_array = array_filter($dir_array);
1321
                $array_len = count($dir_array) + 1;
1322
                $real_dir = '';
1323
1324
                for ($i = 1; $i < $array_len; $i++) {
1325
                    $real_dir .= '/'.(isset($dir_array[$i]) ? $dir_array[$i] : '');
1326
                    $parent_id = self::get_document_id($course_info, $real_dir);
1327
                    if ($session_id != 0 && empty($parent_id)) {
1328
                        $parent_id = self::get_document_id($course_info, $real_dir, 0);
1329
                    }
1330
                    if (!empty($parent_id)) {
1331
                        $sub_document_data = self::get_document_data_by_id(
1332
                            $parent_id,
1333
                            $course_code,
1334
                            false,
1335
                            $session_id
1336
                        );
1337
                        if ($session_id != 0 and !$sub_document_data) {
1338
                            $sub_document_data = self::get_document_data_by_id(
1339
                                $parent_id,
1340
                                $course_code,
1341
                                false,
1342
                                0
1343
                            );
1344
                        }
1345
                        //@todo add visibility here
1346
                        $parents[] = $sub_document_data;
1347
                    }
1348
                }
1349
            }
1350
            $row['parents'] = $parents;
1351
1352
            return $row;
1353
        }
1354
1355
        return false;
1356
    }
1357
1358
    /**
1359
     * Allow to set a specific document as a new template for CKeditor
1360
     * for a particular user in a particular course.
1361
     *
1362
     * @param string $title
1363
     * @param string $description
1364
     * @param int    $document_id_for_template the document id
1365
     * @param int    $courseId
1366
     * @param int    $user_id
1367
     * @param string $image
1368
     *
1369
     * @return bool
1370
     */
1371
    public static function setDocumentAsTemplate(
1372
        $title,
1373
        $description,
1374
        $document_id_for_template,
1375
        $courseId,
1376
        $user_id,
1377
        $image
1378
    ) {
1379
        // Database table definition
1380
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1381
        $params = [
1382
            'title' => $title,
1383
            'description' => $description,
1384
            'c_id' => $courseId,
1385
            'user_id' => $user_id,
1386
            'ref_doc' => $document_id_for_template,
1387
            'image' => $image,
1388
        ];
1389
        Database::insert($table_template, $params);
1390
1391
        return true;
1392
    }
1393
1394
    /**
1395
     * Unset a document as template.
1396
     *
1397
     * @param int $document_id
1398
     * @param int $courseId
1399
     * @param int $user_id
1400
     */
1401
    public static function unsetDocumentAsTemplate(
1402
        $document_id,
1403
        $courseId,
1404
        $user_id
1405
    ) {
1406
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1407
        $courseId = (int) $courseId;
1408
        $user_id = (int) $user_id;
1409
        $document_id = (int) $document_id;
1410
1411
        $sql = 'SELECT id FROM '.$table_template.'
1412
                WHERE
1413
                    c_id = "'.$courseId.'" AND
1414
                    user_id = "'.$user_id.'" AND
1415
                    ref_doc = "'.$document_id.'"';
1416
        $result = Database::query($sql);
1417
        $template_id = Database::result($result, 0, 0);
1418
1419
        my_delete(api_get_path(SYS_CODE_PATH).'upload/template_thumbnails/'.$template_id.'.jpg');
1420
1421
        $sql = 'DELETE FROM '.$table_template.'
1422
                WHERE
1423
                    c_id ="'.$courseId.'" AND
1424
                    user_id="'.$user_id.'" AND
1425
                    ref_doc="'.$document_id.'"';
1426
1427
        Database::query($sql);
1428
    }
1429
1430
    /**
1431
     * Return true if the documentpath have visibility=1 as
1432
     * item_property (you should use the is_visible_by_id).
1433
     *
1434
     * @param string $doc_path the relative complete path of the document
1435
     * @param array  $course   the _course array info of the document's course
1436
     * @param int
1437
     * @param string
1438
     *
1439
     * @return bool
1440
     */
1441
    public static function is_visible(
1442
        $doc_path,
1443
        $course,
1444
        $session_id = 0,
1445
        $file_type = 'file'
1446
    ) {
1447
        $docTable = Database::get_course_table(TABLE_DOCUMENT);
1448
1449
        $course_id = $course['real_id'];
1450
        // note the extra / at the end of doc_path to match every path in
1451
        // the document table that is part of the document path
1452
1453
        $session_id = intval($session_id);
1454
        $condition = " AND d.session_id IN  ('$session_id', '0') ";
1455
        // The " d.filetype='file' " let the user see a file even if the folder is hidden see #2198
1456
1457
        /*
1458
          When using hotpotatoes files, a new html files are generated
1459
          in the hotpotatoes folder to display the test.
1460
          The genuine html file is copied to math4.htm(user_id).t.html
1461
          Images files are not copied, and keep same name.
1462
          To check the html file visibility, we don't have to check file math4.htm(user_id).t.html but file math4.htm
1463
          In this case, we have to remove (user_id).t.html to check the visibility of the file
1464
          For images, we just check the path of the image file.
1465
1466
          Exemple of hotpotatoes folder :
1467
          A.jpg
1468
          maths4-consigne.jpg
1469
          maths4.htm
1470
          maths4.htm1.t.html
1471
          maths4.htm52.t.html
1472
          maths4.htm654.t.html
1473
          omega.jpg
1474
          theta.jpg
1475
         */
1476
1477
        if (strpos($doc_path, 'HotPotatoes_files') && preg_match("/\.t\.html$/", $doc_path)) {
1478
            $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
1479
        }
1480
1481
        if (!in_array($file_type, ['file', 'folder'])) {
1482
            $file_type = 'file';
1483
        }
1484
        $doc_path = Database::escape_string($doc_path).'/';
1485
1486
        $sql = "SELECT iid
1487
                FROM $docTable d
1488
        		WHERE
1489
        		    d.c_id  = $course_id AND 
1490
        		    $condition AND
1491
        			filetype = '$file_type' AND
1492
        			locate(concat(path,'/'), '$doc_path')=1
1493
                ";
1494
1495
        $result = Database::query($sql);
1496
        $is_visible = false;
1497
        if (Database::num_rows($result) > 0) {
1498
            $row = Database::fetch_array($result, 'ASSOC');
1499
1500
            $em = Database::getManager();
1501
1502
            $repo = $em->getRepository('ChamiloCourseBundle:CDocument');
1503
            /** @var \Chamilo\CourseBundle\Entity\CDocument $document */
1504
            $document = $repo->find($row['iid']);
1505
            if ($document->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED) {
1506
                $is_visible = api_is_allowed_in_course() || api_is_platform_admin();
1507
            }
1508
        }
1509
1510
        /* improved protection of documents viewable directly through the url:
1511
            incorporates the same protections of the course at the url of
1512
            documents:
1513
            access allowed for the whole world Open, access allowed for
1514
            users registered on the platform Private access, document accessible
1515
            only to course members (see the Users list), Completely closed;
1516
            the document is only accessible to the course admin and
1517
            teaching assistants.*/
1518
        //return $_SESSION ['is_allowed_in_course'] || api_is_platform_admin();
1519
        return $is_visible;
1520
    }
1521
1522
    /**
1523
     * Return true if user can see a file.
1524
     *
1525
     * @param   int     document id
1526
     * @param   array   course info
1527
     * @param   int
1528
     * @param   int
1529
     * @param bool
1530
     *
1531
     * @return bool
1532
     */
1533
    public static function is_visible_by_id(
1534
        $doc_id,
1535
        $course_info,
1536
        $session_id,
1537
        $user_id,
1538
        $admins_can_see_everything = true,
1539
        $userIsSubscribed = null
1540
    ) {
1541
        $user_in_course = false;
1542
1543
        //1. Checking the course array
1544
        if (empty($course_info)) {
1545
            $course_info = api_get_course_info();
1546
            if (empty($course_info)) {
1547
                return false;
1548
            }
1549
        }
1550
1551
        $doc_id = (int) $doc_id;
1552
        $session_id = (int) $session_id;
1553
        // 2. Course and Session visibility are handle in local.inc.php/global.inc.php
1554
        // 3. Checking if user exist in course/session
1555
        if ($session_id == 0) {
1556
            if (is_null($userIsSubscribed)) {
1557
                $userIsSubscribed = CourseManager::is_user_subscribed_in_course(
1558
                    $user_id,
1559
                    $course_info['code']
1560
                );
1561
            }
1562
1563
            if ($userIsSubscribed === true || api_is_platform_admin()) {
1564
                $user_in_course = true;
1565
            }
1566
1567
            // Check if course is open then we can consider that the student is registered to the course
1568
            if (isset($course_info) &&
1569
                in_array(
1570
                    $course_info['visibility'],
1571
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
1572
                )
1573
            ) {
1574
                $user_in_course = true;
1575
            }
1576
        } else {
1577
            $user_status = SessionManager::get_user_status_in_course_session(
1578
                $user_id,
1579
                $course_info['real_id'],
1580
                $session_id
1581
            );
1582
1583
            if (in_array($user_status, ['0', '2', '6'])) {
1584
                //is true if is an student, course session teacher or coach
1585
                $user_in_course = true;
1586
            }
1587
1588
            if (api_is_platform_admin()) {
1589
                $user_in_course = true;
1590
            }
1591
        }
1592
1593
        $em = Database::getManager();
1594
1595
        // 4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
1596
        if ($user_in_course) {
1597
            $repo = $em->getRepository('ChamiloCourseBundle:CDocument');
1598
            /** @var \Chamilo\CourseBundle\Entity\CDocument $document */
1599
            $document = $repo->find($doc_id);
1600
1601
            if ($document->isVisible()) {
1602
                return true;
1603
            }
1604
1605
            return false;
1606
1607
            // 4.1 Checking document visibility for a Course
1608
            if ($session_id == 0) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

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

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

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

    return false;
}

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

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