Passed
Push — master ( ad5dd8...3078de )
by Julito
08:55
created

DocumentManager::resizeImageSlideShow()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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