Completed
Push — master ( f41061...196bfc )
by Julito
09:03
created

DocumentManager::generateMediaPreview()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 17
rs 9.8333
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Resource\ResourceFile;
5
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
6
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
7
use Chamilo\CoreBundle\Framework\Container;
8
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
9
use Chamilo\CourseBundle\Entity\CDocument;
10
use Chamilo\CourseBundle\Entity\CGroupInfo;
11
use Chamilo\UserBundle\Entity\User;
12
use ChamiloSession as Session;
13
use Symfony\Component\HttpFoundation\File\UploadedFile;
14
15
/**
16
 *  Class DocumentManager
17
 *  This is the document library for Chamilo.
18
 *  It is / will be used to provide a service layer to all document-using tools.
19
 *  and eliminate code duplication fro group documents, scorm documents, main documents.
20
 *  Include/require it in your code to use its functionality.
21
 *
22
 * @package chamilo.library
23
 */
24
class DocumentManager
25
{
26
    /**
27
     * Construct.
28
     */
29
    private function __construct()
30
    {
31
    }
32
33
    /**
34
     * @param string $course_code
35
     *
36
     * @return int the document folder quota for the current course in bytes
37
     *             or the default quota
38
     */
39
    public static function get_course_quota($course_code = null)
40
    {
41
        if (empty($course_code)) {
42
            $course_info = api_get_course_info();
43
        } else {
44
            $course_info = api_get_course_info($course_code);
45
        }
46
47
        $course_quota = null;
48
        if (empty($course_info)) {
49
            return DEFAULT_DOCUMENT_QUOTA;
50
        } else {
51
            $course_quota = $course_info['disk_quota'];
52
        }
53
        if (is_null($course_quota) || empty($course_quota)) {
54
            // Course table entry for quota was null, then use default value
55
            $course_quota = DEFAULT_DOCUMENT_QUOTA;
56
        }
57
58
        return $course_quota;
59
    }
60
61
    /**
62
     * Get the content type of a file by checking the extension
63
     * We could use mime_content_type() with php-versions > 4.3,
64
     * but this doesn't work as it should on Windows installations.
65
     *
66
     * @param string $filename or boolean TRUE to return complete array
67
     *
68
     * @author ? first version
69
     * @author Bert Vanderkimpen
70
     *
71
     * @return string
72
     */
73
    public static function file_get_mime_type($filename)
74
    {
75
        // All MIME types in an array (from 1.6, this is the authorative source)
76
        // Please, keep this alphabetical if you add something to this list!
77
        $mimeTypes = [
78
            'ai' => 'application/postscript',
79
            'aif' => 'audio/x-aiff',
80
            'aifc' => 'audio/x-aiff',
81
            'aiff' => 'audio/x-aiff',
82
            'asf' => 'video/x-ms-asf',
83
            'asc' => 'text/plain',
84
            'au' => 'audio/basic',
85
            'avi' => 'video/x-msvideo',
86
            'bcpio' => 'application/x-bcpio',
87
            'bin' => 'application/octet-stream',
88
            'bmp' => 'image/bmp',
89
            'cdf' => 'application/x-netcdf',
90
            'class' => 'application/octet-stream',
91
            'cpio' => 'application/x-cpio',
92
            'cpt' => 'application/mac-compactpro',
93
            'csh' => 'application/x-csh',
94
            'css' => 'text/css',
95
            'dcr' => 'application/x-director',
96
            'dir' => 'application/x-director',
97
            'djv' => 'image/vnd.djvu',
98
            'djvu' => 'image/vnd.djvu',
99
            'dll' => 'application/octet-stream',
100
            'dmg' => 'application/x-diskcopy',
101
            'dms' => 'application/octet-stream',
102
            'doc' => 'application/msword',
103
            'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
104
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
105
            'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
106
            'dvi' => 'application/x-dvi',
107
            'dwg' => 'application/vnd.dwg',
108
            'dwf' => 'application/vnd.dwf',
109
            'dxf' => 'application/vnd.dxf',
110
            'dxr' => 'application/x-director',
111
            'eps' => 'application/postscript',
112
            'epub' => 'application/epub+zip',
113
            'etx' => 'text/x-setext',
114
            'exe' => 'application/octet-stream',
115
            'ez' => 'application/andrew-inset',
116
            'flv' => 'video/flv',
117
            'gif' => 'image/gif',
118
            'gtar' => 'application/x-gtar',
119
            'gz' => 'application/x-gzip',
120
            'hdf' => 'application/x-hdf',
121
            'hqx' => 'application/mac-binhex40',
122
            'htm' => 'text/html',
123
            'html' => 'text/html',
124
            'ice' => 'x-conference-xcooltalk',
125
            'ief' => 'image/ief',
126
            'iges' => 'model/iges',
127
            'igs' => 'model/iges',
128
            'jar' => 'application/java-archiver',
129
            'jpe' => 'image/jpeg',
130
            'jpeg' => 'image/jpeg',
131
            'jpg' => 'image/jpeg',
132
            'js' => 'application/x-javascript',
133
            'kar' => 'audio/midi',
134
            'lam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
135
            'latex' => 'application/x-latex',
136
            'lha' => 'application/octet-stream',
137
            'log' => 'text/plain',
138
            'lzh' => 'application/octet-stream',
139
            'm1a' => 'audio/mpeg',
140
            'm2a' => 'audio/mpeg',
141
            'm3u' => 'audio/x-mpegurl',
142
            'man' => 'application/x-troff-man',
143
            'me' => 'application/x-troff-me',
144
            'mesh' => 'model/mesh',
145
            'mid' => 'audio/midi',
146
            'midi' => 'audio/midi',
147
            'mov' => 'video/quicktime',
148
            'movie' => 'video/x-sgi-movie',
149
            'mp2' => 'audio/mpeg',
150
            'mp3' => 'audio/mpeg',
151
            'mp4' => 'video/mp4',
152
            'mpa' => 'audio/mpeg',
153
            'mpe' => 'video/mpeg',
154
            'mpeg' => 'video/mpeg',
155
            'mpg' => 'video/mpeg',
156
            'mpga' => 'audio/mpeg',
157
            'ms' => 'application/x-troff-ms',
158
            'msh' => 'model/mesh',
159
            'mxu' => 'video/vnd.mpegurl',
160
            'nc' => 'application/x-netcdf',
161
            'oda' => 'application/oda',
162
            'oga' => 'audio/ogg',
163
            'ogg' => 'application/ogg',
164
            'ogx' => 'application/ogg',
165
            'ogv' => 'video/ogg',
166
            'pbm' => 'image/x-portable-bitmap',
167
            'pct' => 'image/pict',
168
            'pdb' => 'chemical/x-pdb',
169
            'pdf' => 'application/pdf',
170
            'pgm' => 'image/x-portable-graymap',
171
            'pgn' => 'application/x-chess-pgn',
172
            'pict' => 'image/pict',
173
            'png' => 'image/png',
174
            'pnm' => 'image/x-portable-anymap',
175
            'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
176
            'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
177
            'pps' => 'application/vnd.ms-powerpoint',
178
            'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
179
            'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
180
            'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
181
            'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
182
            'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
183
            'ppm' => 'image/x-portable-pixmap',
184
            'ppt' => 'application/vnd.ms-powerpoint',
185
            'ps' => 'application/postscript',
186
            'qt' => 'video/quicktime',
187
            'ra' => 'audio/x-realaudio',
188
            'ram' => 'audio/x-pn-realaudio',
189
            'rar' => 'image/x-rar-compressed',
190
            'ras' => 'image/x-cmu-raster',
191
            'rgb' => 'image/x-rgb',
192
            'rm' => 'audio/x-pn-realaudio',
193
            'roff' => 'application/x-troff',
194
            'rpm' => 'audio/x-pn-realaudio-plugin',
195
            'rtf' => 'text/rtf',
196
            'rtx' => 'text/richtext',
197
            'sgm' => 'text/sgml',
198
            'sgml' => 'text/sgml',
199
            'sh' => 'application/x-sh',
200
            'shar' => 'application/x-shar',
201
            'silo' => 'model/mesh',
202
            'sib' => 'application/X-Sibelius-Score',
203
            'sit' => 'application/x-stuffit',
204
            'skd' => 'application/x-koan',
205
            'skm' => 'application/x-koan',
206
            'skp' => 'application/x-koan',
207
            'skt' => 'application/x-koan',
208
            'smi' => 'application/smil',
209
            'smil' => 'application/smil',
210
            'snd' => 'audio/basic',
211
            'so' => 'application/octet-stream',
212
            'spl' => 'application/x-futuresplash',
213
            'src' => 'application/x-wais-source',
214
            'sv4cpio' => 'application/x-sv4cpio',
215
            'sv4crc' => 'application/x-sv4crc',
216
            'svf' => 'application/vnd.svf',
217
            'svg' => 'image/svg+xml',
218
            //'svgz' => 'image/svg+xml',
219
            'swf' => 'application/x-shockwave-flash',
220
            'sxc' => 'application/vnd.sun.xml.calc',
221
            'sxi' => 'application/vnd.sun.xml.impress',
222
            'sxw' => 'application/vnd.sun.xml.writer',
223
            't' => 'application/x-troff',
224
            'tar' => 'application/x-tar',
225
            'tcl' => 'application/x-tcl',
226
            'tex' => 'application/x-tex',
227
            'texi' => 'application/x-texinfo',
228
            'texinfo' => 'application/x-texinfo',
229
            'tga' => 'image/x-targa',
230
            'tif' => 'image/tif',
231
            'tiff' => 'image/tiff',
232
            'tr' => 'application/x-troff',
233
            'tsv' => 'text/tab-seperated-values',
234
            'txt' => 'text/plain',
235
            'ustar' => 'application/x-ustar',
236
            'vcd' => 'application/x-cdlink',
237
            'vrml' => 'model/vrml',
238
            'wav' => 'audio/x-wav',
239
            'wbmp' => 'image/vnd.wap.wbmp',
240
            'wbxml' => 'application/vnd.wap.wbxml',
241
            'webp' => 'image/webp',
242
            'wml' => 'text/vnd.wap.wml',
243
            'wmlc' => 'application/vnd.wap.wmlc',
244
            'wmls' => 'text/vnd.wap.wmlscript',
245
            'wmlsc' => 'application/vnd.wap.wmlscriptc',
246
            'wma' => 'audio/x-ms-wma',
247
            'wmv' => 'video/x-ms-wmv',
248
            'wrl' => 'model/vrml',
249
            'xbm' => 'image/x-xbitmap',
250
            'xht' => 'application/xhtml+xml',
251
            'xhtml' => 'application/xhtml+xml',
252
            'xls' => 'application/vnd.ms-excel',
253
            'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
254
            'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
255
            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
256
            'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
257
            'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
258
            'xml' => 'text/xml',
259
            'xpm' => 'image/x-xpixmap',
260
            'xsl' => 'text/xml',
261
            'xwd' => 'image/x-windowdump',
262
            'xyz' => 'chemical/x-xyz',
263
            'zip' => 'application/zip',
264
        ];
265
266
        if ($filename === true) {
267
            return $mimeTypes;
268
        }
269
270
        // Get the extension of the file
271
        $extension = explode('.', $filename);
272
273
        // $filename will be an array if a . was found
274
        if (is_array($extension)) {
275
            $extension = strtolower($extension[count($extension) - 1]);
276
        } else {
277
            //file without extension
278
            $extension = 'empty';
279
        }
280
281
        //if the extension is found, return the content type
282
        if (isset($mimeTypes[$extension])) {
283
            return $mimeTypes[$extension];
284
        }
285
286
        return 'application/octet-stream';
287
    }
288
289
    /**
290
     * This function smart streams a file to the client using HTTP headers.
291
     *
292
     * @param string $fullFilename The full path of the file to be sent
293
     * @param string $filename     The name of the file as shown to the client
294
     * @param string $contentType  The MIME type of the file
295
     *
296
     * @return bool false if file doesn't exist, true if stream succeeded
297
     */
298
    public static function smartReadFile($fullFilename, $filename, $contentType = 'application/octet-stream')
299
    {
300
        if (!file_exists($fullFilename)) {
301
            header("HTTP/1.1 404 Not Found");
302
303
            return false;
304
        }
305
306
        $size = filesize($fullFilename);
307
        $time = date('r', filemtime($fullFilename));
308
309
        $fm = @fopen($fullFilename, 'rb');
310
        if (!$fm) {
0 ignored issues
show
introduced by
$fm is of type false|resource, thus it always evaluated to false.
Loading history...
311
            header("HTTP/1.1 505 Internal server error");
312
313
            return false;
314
        }
315
316
        $begin = 0;
317
        $end = $size - 1;
318
319
        if (isset($_SERVER['HTTP_RANGE'])) {
320
            if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
321
                $begin = intval($matches[1]);
322
                if (!empty($matches[2])) {
323
                    $end = intval($matches[2]);
324
                }
325
            }
326
        }
327
328
        if (isset($_SERVER['HTTP_RANGE'])) {
329
            header('HTTP/1.1 206 Partial Content');
330
        } else {
331
            header('HTTP/1.1 200 OK');
332
        }
333
334
        header("Content-Type: $contentType");
335
        header('Cache-Control: public, must-revalidate, max-age=0');
336
        header('Pragma: no-cache');
337
        header('Accept-Ranges: bytes');
338
        header('Content-Length:'.(($end - $begin) + 1));
339
        if (isset($_SERVER['HTTP_RANGE'])) {
340
            header("Content-Range: bytes $begin-$end/$size");
341
        }
342
        header("Content-Disposition: inline; filename=$filename");
343
        header("Content-Transfer-Encoding: binary");
344
        header("Last-Modified: $time");
345
346
        $cur = $begin;
347
        fseek($fm, $begin, 0);
348
349
        while (!feof($fm) && $cur <= $end && (connection_status() == 0)) {
350
            echo fread($fm, min(1024 * 16, ($end - $cur) + 1));
351
            $cur += 1024 * 16;
352
        }
353
    }
354
355
    /**
356
     * This function streams a file to the client.
357
     *
358
     * @param string $full_file_name
359
     * @param bool   $forced
360
     * @param string $name
361
     * @param bool   $fixLinksHttpToHttps change file content from http to https
362
     *
363
     * @return false if file doesn't exist, true if stream succeeded
364
     */
365
    public static function file_send_for_download(
366
        $full_file_name,
367
        $forced = false,
368
        $name = '',
369
        $fixLinksHttpToHttps = false
370
    ) {
371
        session_write_close(); //we do not need write access to session anymore
372
        if (!is_file($full_file_name)) {
373
            return false;
374
        }
375
        $filename = $name == '' ? basename($full_file_name) : api_replace_dangerous_char($name);
376
        $len = filesize($full_file_name);
377
        // Fixing error when file name contains a ","
378
        $filename = str_replace(',', '', $filename);
379
        $sendFileHeaders = api_get_configuration_value('enable_x_sendfile_headers');
380
381
        // Allows chrome to make videos and audios seekable
382
        header('Accept-Ranges: bytes');
383
384
        if ($forced) {
385
            // Force the browser to save the file instead of opening it
386
            if (isset($sendFileHeaders) &&
387
                !empty($sendFileHeaders)) {
388
                header("X-Sendfile: $filename");
389
            }
390
391
            header('Content-type: application/octet-stream');
392
            header('Content-length: '.$len);
393
            if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
394
                header('Content-Disposition: filename= '.$filename);
395
            } else {
396
                header('Content-Disposition: attachment; filename= '.$filename);
397
            }
398
            if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
399
                header('Pragma: ');
400
                header('Cache-Control: ');
401
                header('Cache-Control: public'); // IE cannot download from sessions without a cache
402
            }
403
            header('Content-Description: '.$filename);
404
            header('Content-Transfer-Encoding: binary');
405
406
            if (function_exists('ob_end_clean') && ob_get_length()) {
407
                // Use ob_end_clean() to avoid weird buffering situations
408
                // where file is sent broken/incomplete for download
409
                ob_end_clean();
410
            }
411
412
            $res = fopen($full_file_name, 'r');
413
            fpassthru($res);
414
415
            return true;
416
        } else {
417
            // no forced download, just let the browser decide what to do according to the mimetype
418
            $lpFixedEncoding = api_get_setting('lp.fixed_encoding') === 'true';
419
420
            // Commented to let courses content to be cached in order to improve performance:
421
            //header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
422
            //header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
423
424
            // Commented to avoid double caching declaration when playing with IE and HTTPS
425
            //header('Cache-Control: no-cache, must-revalidate');
426
            //header('Pragma: no-cache');
427
428
            $contentType = self::file_get_mime_type($filename);
429
430
            switch ($contentType) {
431
                case 'text/html':
432
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
433
                        $contentType .= '; charset=UTF-8';
434
                    } else {
435
                        $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
436
                        if (!empty($encoding)) {
437
                            $contentType .= '; charset='.$encoding;
438
                        }
439
                    }
440
                    break;
441
                case 'text/plain':
442
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
443
                        $contentType .= '; charset=UTF-8';
444
                    } else {
445
                        $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
446
                        if (!empty($encoding)) {
447
                            $contentType .= '; charset='.$encoding;
448
                        }
449
                    }
450
                    break;
451
                case 'video/mp4':
452
                case 'audio/mpeg':
453
                case 'audio/mp4':
454
                case 'audio/ogg':
455
                case 'audio/webm':
456
                case 'audio/wav':
457
                case 'video/ogg':
458
                case 'video/webm':
459
                    self::smartReadFile($full_file_name, $filename, $contentType);
460
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
461
                case 'application/vnd.dwg':
462
                case 'application/vnd.dwf':
463
                    header('Content-type: application/octet-stream');
464
                    break;
465
            }
466
467
            header('Content-type: '.$contentType);
468
            header('Content-Length: '.$len);
469
            $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);
470
471
            if (strpos($userAgent, 'msie')) {
472
                header('Content-Disposition: ; filename= '.$filename);
473
            } else {
474
                //header('Content-Disposition: inline');
475
                header('Content-Disposition: inline;');
476
            }
477
478
            if ($fixLinksHttpToHttps) {
479
                $content = file_get_contents($full_file_name);
480
                $content = str_replace(
481
                    ['http%3A%2F%2F', 'http://'],
482
                    ['https%3A%2F%2F', 'https://'],
483
                    $content
484
                );
485
                echo $content;
486
            } else {
487
                if (function_exists('ob_end_clean') && ob_get_length()) {
488
                    // Use ob_end_clean() to avoid weird buffering situations
489
                    // where file is sent broken/incomplete for download
490
                    ob_end_clean();
491
                }
492
493
                readfile($full_file_name);
494
            }
495
496
            return true;
497
        }
498
    }
499
500
    /**
501
     * Session folder filters.
502
     *
503
     * @param string $path
504
     * @param int    $sessionId
505
     *
506
     * @return string|null
507
     */
508
    public static function getSessionFolderFilters($path, $sessionId)
509
    {
510
        $sessionId = (int) $sessionId;
511
        $condition = null;
512
513
        if (!empty($sessionId)) {
514
            // Chat folder filter
515
            if ($path == '/chat_files') {
516
                $condition .= " AND (docs.session_id = '$sessionId') ";
517
            }
518
            // share_folder filter
519
            $condition .= " AND docs.path != '/shared_folder' ";
520
        }
521
522
        return $condition;
523
    }
524
525
    /**
526
     * Fetches all document data for the given user/group.
527
     *
528
     * @param array     $courseInfo
529
     * @param string    $path
530
     * @param int       $toGroupId       iid
531
     * @param int       $toUserId
532
     * @param bool      $canSeeInvisible
533
     * @param bool      $search
534
     * @param int       $sessionId
535
     * @param User|null $currentUser
536
     *
537
     * @return array with all document data
538
     */
539
    public static function getAllDocumentData(
540
        $courseInfo,
541
        $path = '/',
542
        $toGroupId = 0,
543
        $toUserId = null,
544
        $canSeeInvisible = false,
545
        $search = false,
546
        $sessionId = 0,
547
        User $currentUser = null
548
    ) {
549
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
550
        $currentUser = $currentUser ?: api_get_current_user();
551
552
        $userGroupFilter = '';
553
        if (!is_null($toUserId)) {
554
            $toUserId = (int) $toUserId;
555
            $userGroupFilter = "last.to_user_id = $toUserId";
556
            if (empty($toUserId)) {
557
                $userGroupFilter = " (last.to_user_id = 0 OR last.to_user_id IS NULL) ";
558
            }
559
        } else {
560
            $toGroupId = (int) $toGroupId;
561
            $userGroupFilter = "last.to_group_id = $toGroupId";
562
            if (empty($toGroupId)) {
563
                $userGroupFilter = "( last.to_group_id = 0 OR last.to_group_id IS NULL) ";
564
            }
565
        }
566
567
        // Escape underscores in the path so they don't act as a wildcard
568
        $originalPath = $path;
569
        $path = str_replace('_', '\_', $path);
570
571
        $visibilityBit = ' <> 2';
572
573
        // The given path will not end with a slash, unless it's the root '/'
574
        // so no root -> add slash
575
        $addedSlash = $path == '/' ? '' : '/';
576
577
        // Condition for the session
578
        $sessionId = $sessionId ?: api_get_session_id();
579
        $conditionSession = " AND (last.session_id = '$sessionId' OR (last.session_id = '0' OR last.session_id IS NULL) )";
580
        $conditionSession .= self::getSessionFolderFilters($originalPath, $sessionId);
581
582
        $sharedCondition = null;
583
        if ($originalPath == '/shared_folder') {
584
            $students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
585
            if (!empty($students)) {
586
                $conditionList = [];
587
                foreach ($students as $studentInfo) {
588
                    $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
589
                }
590
                $sharedCondition .= ' AND docs.path IN ("'.implode('","', $conditionList).'")';
591
            }
592
        }
593
594
        $sql = "SELECT
595
                    docs.id,
596
                    docs.filetype,
597
                    docs.path,
598
                    docs.title,
599
                    docs.comment,
600
                    docs.size,
601
                    docs.readonly,
602
                    docs.session_id,
603
                    creator_id,
604
                    visibility,
605
                    n.updated_at,
606
                    n.created_at,
607
                    n.creator_id                                     
608
                FROM resource_node AS n
609
                INNER JOIN $tblDocument AS docs
610
                ON (docs.resource_node_id = n.id)
611
                INNER JOIN resource_link l
612
                ON (l.resource_node_id = n.id)                
613
                WHERE
614
                    docs.c_id = {$courseInfo['real_id']} AND                    
615
                    docs.path LIKE '".Database::escape_string($path.$addedSlash.'%')."' AND
616
                    docs.path NOT LIKE '".Database::escape_string($path.$addedSlash.'%/%')."' AND
617
                    docs.path NOT LIKE '%_DELETED_%' AND
618
                    l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')
619
                    $sharedCondition               
620
                ";
621
        //$userGroupFilter AND
622
        //$conditionSession
623
        $result = Database::query($sql);
624
625
        $documentData = [];
626
        $isAllowedToEdit = api_is_allowed_to_edit(null, true);
627
        $isCoach = api_is_coach();
628
        if ($result !== false && Database::num_rows($result) != 0) {
629
            $rows = [];
630
631
            $hideInvisibleDocuments = api_get_configuration_value('hide_invisible_course_documents_in_sessions');
632
633
            while ($row = Database::fetch_array($result, 'ASSOC')) {
634
                if (isset($rows[$row['id']])) {
635
                    continue;
636
                }
637
638
                // If we are in session and hide_invisible_course_documents_in_sessions is enabled
639
                // Then we avoid the documents that have visibility in session but that they come from a base course
640
                if ($hideInvisibleDocuments && $sessionId) {
641
                    if ($row['item_property_session_id'] == $sessionId && empty($row['session_id'])) {
642
                        continue;
643
                    }
644
                }
645
646
                $rows[$row['id']] = $row;
647
            }
648
649
            // If we are in session and hide_invisible_course_documents_in_sessions is enabled
650
            // Or if we are students
651
            // Then don't list the invisible or deleted documents
652
            if (($sessionId && $hideInvisibleDocuments) || (!$isCoach && !$isAllowedToEdit)) {
653
                $rows = array_filter($rows, function ($row) {
654
                    if (in_array(
655
                        $row['visibility'],
656
                        [
657
                            ResourceLink::VISIBILITY_DELETED,
658
                            ResourceLink::VISIBILITY_DRAFT,
659
                        ]
660
                    )) {
661
                        return false;
662
                    }
663
664
                    return true;
665
                });
666
            }
667
668
            foreach ($rows as $row) {
669
                if ($row['filetype'] == 'file' &&
670
                    pathinfo($row['path'], PATHINFO_EXTENSION) == 'html'
671
                ) {
672
                    // Templates management
673
                    $tblTemplate = Database::get_main_table(TABLE_MAIN_TEMPLATES);
674
                    $sql = "SELECT id FROM $tblTemplate
675
                            WHERE
676
                                c_id = '".$courseInfo['real_id']."' AND
677
                                user_id = '".$currentUser->getId()."' AND
678
                                ref_doc = '".$row['id']."'";
679
                    $templateResult = Database::query($sql);
680
                    $row['is_template'] = (Database::num_rows($templateResult) > 0) ? 1 : 0;
681
                }
682
                $row['basename'] = basename($row['path']);
683
                // Just filling $document_data.
684
                $documentData[$row['id']] = $row;
685
            }
686
687
            // Only for the student we filter the results see BT#1652
688
            if (!$isCoach && !$isAllowedToEdit) {
689
                // Checking parents visibility.
690
                $finalDocumentData = [];
691
                foreach ($documentData as $row) {
692
                    $isVisible = self::check_visibility_tree(
693
                        $row['id'],
694
                        $courseInfo,
695
                        $sessionId,
696
                        $currentUser->getId(),
697
                        $toGroupId
698
                    );
699
                    if ($isVisible) {
700
                        $finalDocumentData[$row['id']] = $row;
701
                    }
702
                }
703
            } else {
704
                $finalDocumentData = $documentData;
705
            }
706
707
            return $finalDocumentData;
708
        } else {
709
            return [];
710
        }
711
    }
712
713
    /**
714
     * Gets the paths of all folders in a course
715
     * can show all folders (except for the deleted ones) or only visible ones.
716
     *
717
     * @param array  $courseInfo
718
     * @param int    $groupIid          iid
719
     * @param bool   $can_see_invisible
720
     * @param bool   $getInvisibleList
721
     * @param string $path              current path
722
     *
723
     * @return array with paths
724
     */
725
    public static function get_all_document_folders(
726
        $courseInfo,
727
        $groupIid = 0,
728
        $can_see_invisible = false,
729
        $getInvisibleList = false,
730
        $path = ''
731
    ) {
732
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
733
        $groupIid = (int) $groupIid;
734
        $courseId = $courseInfo['real_id'];
735
        $sessionId = api_get_session_id();
736
737
        $folders = [];
738
        $students = CourseManager::get_user_list_from_course_code(
739
            $courseInfo['code'],
740
            api_get_session_id()
741
        );
742
743
        $conditionList = [];
744
        if (!empty($students)) {
745
            foreach ($students as $studentId => $studentInfo) {
746
                $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
747
            }
748
        }
749
750
        $groupCondition = " l.group_id = $groupIid";
751
        if (empty($groupIid)) {
752
            $groupCondition = ' (l.group_id = 0 OR l.group_id IS NULL)';
753
        }
754
755
        $show_users_condition = '';
756
        if (api_get_setting('show_users_folders') === 'false') {
757
            $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
758
        }
759
760
        if ($can_see_invisible) {
761
            $sessionId = $sessionId ?: api_get_session_id();
762
            $condition_session = " AND (l.session_id = '$sessionId' OR (l.session_id = '0' OR l.session_id IS NULL) )";
763
            $condition_session .= self::getSessionFolderFilters($path, $sessionId);
764
765
            $sql = "SELECT DISTINCT docs.id, docs.path
766
                    FROM resource_node AS n
767
                    INNER JOIN $TABLE_DOCUMENT  AS docs
768
                    ON (docs.resource_node_id = n.id)
769
                    INNER JOIN resource_link l
770
                    ON (l.resource_node_id = n.id)
771
                    WHERE                      
772
                        docs.c_id = $courseId AND
773
                        docs.filetype = 'folder' AND
774
                        $groupCondition AND
775
                        docs.path NOT LIKE '%shared_folder%' AND
776
                        docs.path NOT LIKE '%_DELETED_%' AND
777
                        l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')                           
778
                        $condition_session ";
779
780
            if ($groupIid != 0) {
781
                $sql .= " AND docs.path NOT LIKE '%shared_folder%' ";
782
            } else {
783
                $sql .= $show_users_condition;
784
            }
785
786
            $result = Database::query($sql);
787
            if ($result && Database::num_rows($result) != 0) {
788
                while ($row = Database::fetch_array($result, 'ASSOC')) {
789
                    if (self::is_folder_to_avoid($row['path'])) {
790
                        continue;
791
                    }
792
793
                    if (strpos($row['path'], '/shared_folder/') !== false) {
794
                        if (!in_array($row['path'], $conditionList)) {
795
                            continue;
796
                        }
797
                    }
798
799
                    $folders[$row['id']] = $row['path'];
800
                }
801
802
                if (!empty($folders)) {
803
                    natsort($folders);
804
                }
805
806
                return $folders;
807
            } else {
808
                return false;
809
            }
810
        } else {
811
            // No invisible folders
812
            // Condition for the session
813
            $condition_session = api_get_session_condition(
814
                $sessionId,
815
                true,
816
                false,
817
                'docs.session_id'
818
            );
819
820
            $visibilityCondition = 'l.visibility = 1';
821
            $fileType = "docs.filetype = 'folder' AND";
822
            if ($getInvisibleList) {
823
                $visibilityCondition = 'l.visibility = 0';
824
                $fileType = '';
825
            }
826
827
            //get visible folders
828
            $sql = "SELECT DISTINCT docs.id, docs.path
829
                    FROM resource_node AS n
830
                    INNER JOIN $TABLE_DOCUMENT  AS docs
831
                    ON (docs.resource_node_id = n.id)
832
                    INNER JOIN resource_link l
833
                    ON (l.resource_node_id = n.id)
834
                    WHERE
835
                        $fileType                        
836
                        $groupCondition AND
837
                        $visibilityCondition
838
                        $show_users_condition
839
                        $condition_session AND                        
840
                        docs.c_id = $courseId ";
841
            $result = Database::query($sql);
842
            $visibleFolders = [];
843
            while ($row = Database::fetch_array($result, 'ASSOC')) {
844
                $visibleFolders[$row['id']] = $row['path'];
845
            }
846
847
            if ($getInvisibleList) {
848
                return $visibleFolders;
849
            }
850
851
            // get invisible folders
852
            $sql = "SELECT DISTINCT docs.id, docs.path
853
                    FROM resource_node AS n
854
                    INNER JOIN $TABLE_DOCUMENT  AS docs
855
                    ON (docs.resource_node_id = n.id)
856
                    INNER JOIN resource_link l
857
                    ON (l.resource_node_id = n.id)
858
                    WHERE                        
859
                        docs.filetype = 'folder' AND                        
860
                        $groupCondition AND                        
861
                        l.visibility IN ('".ResourceLink::VISIBILITY_PENDING."') 
862
                        $condition_session AND                        
863
                        docs.c_id = $courseId ";
864
            $result = Database::query($sql);
865
            $invisibleFolders = [];
866
            while ($row = Database::fetch_array($result, 'ASSOC')) {
867
                //get visible folders in the invisible ones -> they are invisible too
868
                $sql = "SELECT DISTINCT docs.id, docs.path
869
                        FROM resource_node AS n
870
                        INNER JOIN $TABLE_DOCUMENT  AS docs
871
                        ON (docs.resource_node_id = n.id)
872
                        INNER JOIN resource_link l
873
                        ON (l.resource_node_id = n.id)
874
                        WHERE                            
875
                            docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
876
                            docs.filetype = 'folder' AND                            
877
                            $groupCondition AND
878
                            l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."') 
879
                            $condition_session AND                            
880
                            docs.c_id = $courseId ";
881
                $folder_in_invisible_result = Database::query($sql);
882
                while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
883
                    $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
884
                }
885
            }
886
887
            // If both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
888
            if (is_array($visibleFolders) && is_array($invisibleFolders)) {
889
                $folders = array_diff($visibleFolders, $invisibleFolders);
890
                natsort($folders);
891
892
                return $folders;
893
            }
894
895
            if (is_array($visibleFolders)) {
896
                natsort($visibleFolders);
897
898
                return $visibleFolders;
899
            }
900
901
            // no visible folders found
902
            return false;
903
        }
904
    }
905
906
    /**
907
     * This check if a document has the readonly property checked, then see if the user
908
     * is the owner of this file, if all this is true then return true.
909
     *
910
     * @param array  $_course
911
     * @param int    $user_id     id of the current user
912
     * @param string $file        path stored in the database (if not defined, $documentId must be used)
913
     * @param int    $document_id in case you don't have the file path ,
914
     *                            insert the id of the file here and leave $file in blank ''
915
     * @param bool   $to_delete
916
     * @param int    $sessionId
917
     *
918
     * @return bool true/false
919
     * */
920
    public static function check_readonly(
921
        $_course,
922
        $user_id,
923
        $file = null,
924
        $document_id = 0,
925
        $to_delete = false,
926
        $sessionId = null,
927
        $documentId = null
928
    ) {
929
        $sessionId = (int) $sessionId;
930
        if (empty($sessionId)) {
931
            $sessionId = api_get_session_id();
932
        }
933
        $document_id = (int) $document_id;
934
        if (empty($document_id)) {
935
            $document_id = self::get_document_id($_course, $file, $sessionId);
936
        }
937
938
        $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
939
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
940
        $course_id = $_course['real_id'];
941
942
        if ($to_delete) {
943
            if (self::isFolder($_course, $document_id)) {
944
                if (!empty($file)) {
945
                    $path = Database::escape_string($file);
946
                    // Check
947
                    $sql = "SELECT td.id, readonly, tp.insert_user_id
948
                            FROM $TABLE_DOCUMENT td 
949
                            INNER JOIN $TABLE_PROPERTY tp
950
                            ON (td.c_id = tp.c_id AND tp.ref= td.id)
951
                            WHERE
952
                                td.c_id = $course_id AND
953
                                tp.c_id = $course_id AND
954
                                td.session_id = $sessionId AND                                
955
                                (path='".$path."' OR path LIKE BINARY '".$path."/%' ) ";
956
                    // Get all id's of documents that are deleted
957
                    $what_to_check_result = Database::query($sql);
958
959
                    if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
960
                        // file with readonly set to 1 exist?
961
                        $readonly_set = false;
962
                        while ($row = Database::fetch_array($what_to_check_result)) {
963
                            //query to delete from item_property table
964
                            if ($row['readonly'] == 1) {
965
                                if (!($row['insert_user_id'] == $user_id)) {
966
                                    $readonly_set = true;
967
                                    break;
968
                                }
969
                            }
970
                        }
971
972
                        if ($readonly_set) {
973
                            return true;
974
                        }
975
                    }
976
                }
977
978
                return false;
979
            }
980
        }
981
982
        if (!empty($document_id)) {
983
            $sql = "SELECT a.insert_user_id, b.readonly
984
                   FROM $TABLE_PROPERTY a 
985
                   INNER JOIN $TABLE_DOCUMENT b
986
                   ON (a.c_id = b.c_id AND a.ref= b.id)
987
                   WHERE
988
            			a.c_id = $course_id AND
989
                        b.c_id = $course_id AND
990
            			a.ref = $document_id 
991
                    LIMIT 1";
992
            $result = Database::query($sql);
993
            $doc_details = Database::fetch_array($result, 'ASSOC');
994
995
            if ($doc_details['readonly'] == 1) {
996
                return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
997
            }
998
        }
999
1000
        return false;
1001
    }
1002
1003
    /**
1004
     * This check if a document is a folder or not.
1005
     *
1006
     * @param array $_course
1007
     * @param int   $id      document id
1008
     *
1009
     * @return bool true/false
1010
     * */
1011
    public static function isFolder($_course, $id)
1012
    {
1013
        $table = Database::get_course_table(TABLE_DOCUMENT);
1014
        if (empty($_course)) {
1015
            return false;
1016
        }
1017
        $course_id = $_course['real_id'];
1018
        $id = (int) $id;
1019
        $sql = "SELECT filetype FROM $table
1020
                WHERE c_id = $course_id AND id= $id";
1021
        $result = Database::fetch_array(Database::query($sql), 'ASSOC');
1022
1023
        return $result['filetype'] === 'folder';
1024
    }
1025
1026
    /**
1027
     * @param int   $document_id
1028
     * @param array $course_info
1029
     * @param int   $session_id
1030
     * @param bool  $remove_content_from_db
1031
     */
1032
    public static function deleteDocumentFromDb(
1033
        $document_id,
1034
        $course_info = [],
1035
        $session_id = 0,
1036
        $remove_content_from_db = false
1037
    ) {
1038
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1039
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
1040
1041
        // Deleting from the DB
1042
        $user_id = api_get_user_id();
1043
        $document_id = intval($document_id);
1044
1045
        if (empty($course_info)) {
1046
            $course_info = api_get_course_info();
1047
        }
1048
1049
        if (empty($session_id)) {
1050
            $session_id = api_get_session_id();
1051
        }
1052
        // Soft DB delete
1053
        api_item_property_update(
1054
            $course_info,
1055
            TOOL_DOCUMENT,
1056
            $document_id,
1057
            'delete',
1058
            $user_id,
1059
            null,
1060
            null,
1061
            null,
1062
            null,
1063
            $session_id
1064
        );
1065
        self::delete_document_from_search_engine($course_info['code'], $document_id);
1066
        self::unsetDocumentAsTemplate($document_id, $course_info['real_id'], $user_id);
1067
1068
        //Hard DB delete
1069
        if ($remove_content_from_db) {
1070
            $sql = "DELETE FROM $TABLE_ITEMPROPERTY
1071
                    WHERE
1072
                        c_id = {$course_info['real_id']} AND
1073
                        ref = ".$document_id." AND
1074
                        tool='".TOOL_DOCUMENT."'";
1075
            Database::query($sql);
1076
1077
            $sql = "DELETE FROM $TABLE_DOCUMENT
1078
                    WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
1079
            Database::query($sql);
1080
        }
1081
    }
1082
1083
    /**
1084
     * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
1085
     * Files/folders that are inside a deleted folder get visibility 2.
1086
     *
1087
     * @param array  $_course
1088
     * @param string $path          Path stored in the database
1089
     * @param string $base_work_dir Path to the documents folder (if not defined, $documentId must be used)
1090
     * @param int    $sessionId     The ID of the session, if any
1091
     * @param int    $documentId    The document id, if available
1092
     * @param int    $groupId       iid
1093
     *
1094
     * @return bool true/false
1095
     *
1096
     * @todo now only files/folders in a folder get visibility 2, we should rename them too.
1097
     * @todo We should be able to get rid of this later when using only documentId (check further usage)
1098
     */
1099
    public static function delete_document(
1100
        $_course,
1101
        $path = null,
1102
        $base_work_dir = null,
1103
        $sessionId = null,
1104
        $documentId = null,
1105
        $groupId = 0
1106
    ) {
1107
        $groupId = (int) $groupId;
1108
        if (empty($groupId)) {
1109
            $groupId = api_get_group_id();
1110
        }
1111
1112
        $sessionId = (int) $sessionId;
1113
        if (empty($sessionId)) {
1114
            $sessionId = api_get_session_id();
1115
        }
1116
1117
        $course_id = $_course['real_id'];
1118
1119
        if (empty($course_id)) {
1120
            return false;
1121
        }
1122
1123
        if (empty($base_work_dir)) {
1124
            return false;
1125
        }
1126
1127
        if (empty($documentId)) {
1128
            $documentId = self::get_document_id($_course, $path, $sessionId);
1129
            $docInfo = self::get_document_data_by_id(
1130
                $documentId,
1131
                $_course['code'],
1132
                false,
1133
                $sessionId
1134
            );
1135
            $path = $docInfo['path'];
1136
        } else {
1137
            $docInfo = self::get_document_data_by_id(
1138
                $documentId,
1139
                $_course['code'],
1140
                false,
1141
                $sessionId
1142
            );
1143
            if (empty($docInfo)) {
1144
                return false;
1145
            }
1146
            $path = $docInfo['path'];
1147
        }
1148
1149
        $em = Database::getManager();
1150
        $documentId = (int) $documentId;
1151
1152
        if (empty($path) || empty($docInfo) || empty($documentId)) {
1153
            return false;
1154
        }
1155
1156
        /** @var CDocument $document */
1157
        $document = $em->getRepository('ChamiloCourseBundle:CDocument')->find($docInfo['iid']);
1158
        $document->setSoftDelete();
1159
        $em->persist($document);
1160
        $em->flush();
1161
1162
        return true;
1163
1164
        $itemInfo = api_get_item_property_info(
0 ignored issues
show
Unused Code introduced by
$itemInfo = api_get_item..., $sessionId, $groupId) is not reachable.

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

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

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

    return false;
}

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

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

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

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

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

    return false;
}

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

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

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
5988
            }
5989
        }
5990
    }
5991
5992
    /**
5993
     * @param array $courseInfo
5994
     * @param int   $sessionId
5995
     *
5996
     * @return bool
5997
     */
5998
    public static function downloadAllDeletedDocument($courseInfo, $sessionId)
5999
    {
6000
        $files = self::getDeletedDocuments($courseInfo, $sessionId);
6001
6002
        if (empty($files)) {
6003
            return false;
6004
        }
6005
6006
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
6007
6008
        // Creating a ZIP file.
6009
        $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
6010
        $zip = new PclZip($tempZipFile);
6011
        foreach ($files as $file) {
6012
            $zip->add(
6013
                $coursePath.$file['path'],
6014
                PCLZIP_OPT_REMOVE_PATH,
6015
                $coursePath
6016
            );
6017
        }
6018
6019
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
6020
            self::file_send_for_download($tempZipFile, true);
6021
            @unlink($tempZipFile);
6022
            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...
6023
        }
6024
    }
6025
6026
    /**
6027
     * Delete documents from a session in a course.
6028
     *
6029
     * @param array $courseInfo
6030
     * @param int   $sessionId
6031
     *
6032
     * @return bool
6033
     */
6034
    public static function deleteDocumentsFromSession($courseInfo, $sessionId)
6035
    {
6036
        if (empty($courseInfo)) {
6037
            return false;
6038
        }
6039
6040
        if (empty($sessionId)) {
6041
            return false;
6042
        }
6043
6044
        $itemPropertyTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
6045
        $documentTable = Database::get_course_table(TABLE_DOCUMENT);
6046
6047
        $conditionSession = api_get_session_condition($sessionId, true, false, 'd.session_id');
6048
        $courseId = $courseInfo['real_id'];
6049
6050
        // get invisible folders
6051
        $sql = "SELECT DISTINCT d.id, path
6052
                FROM $itemPropertyTable i
6053
                INNER JOIN $documentTable d
6054
                ON (i.c_id = d.c_id)
6055
                WHERE
6056
                    d.id = i.ref AND
6057
                    i.tool = '".TOOL_DOCUMENT."'
6058
                    $conditionSession AND
6059
                    i.c_id = $courseId AND
6060
                    d.c_id = $courseId ";
6061
6062
        $result = Database::query($sql);
6063
        $documents = Database::store_result($result, 'ASSOC');
6064
        if ($documents) {
6065
            $course_dir = $courseInfo['directory'].'/document';
6066
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
6067
            $base_work_dir = $sys_course_path.$course_dir;
6068
6069
            foreach ($documents as $document) {
6070
                $documentId = $document['id'];
6071
                self::delete_document(
6072
                    $courseInfo,
6073
                    null,
6074
                    $base_work_dir,
6075
                    $sessionId,
6076
                    $documentId
6077
                );
6078
            }
6079
        }
6080
6081
        $sql = "DELETE FROM $documentTable
6082
                WHERE c_id = $courseId AND session_id = $sessionId";
6083
        Database::query($sql);
6084
6085
        $sql = "DELETE FROM $itemPropertyTable
6086
                WHERE c_id = $courseId AND session_id = $sessionId AND tool = '".TOOL_DOCUMENT."'";
6087
        Database::query($sql);
6088
    }
6089
6090
    /**
6091
     * Update the file or directory path in the document db document table.
6092
     *
6093
     * @author - Hugues Peeters <[email protected]>
6094
     *
6095
     * @param string $action   - action type require : 'delete' or 'update'
6096
     * @param string $old_path - old path info stored to change
6097
     * @param string $new_path - new path info to substitute
6098
     *
6099
     * @desc Update the file or directory path in the document db document table
6100
     */
6101
    public static function updateDbInfo($action, $old_path, $new_path = '')
6102
    {
6103
        $dbTable = Database::get_course_table(TABLE_DOCUMENT);
6104
        $course_id = api_get_course_int_id();
6105
        $old_path = Database::escape_string($old_path);
6106
        switch ($action) {
6107
            case 'delete':
6108
                $query = "DELETE FROM $dbTable
6109
                          WHERE
6110
                            c_id = $course_id AND
6111
                            (
6112
                                path LIKE BINARY '".$old_path."' OR
6113
                                path LIKE BINARY '".$old_path."/%'
6114
                            )";
6115
                Database::query($query);
6116
                break;
6117
            case 'update':
6118
                if ($new_path[0] == '.') {
6119
                    $new_path = substr($new_path, 1);
6120
                }
6121
                $new_path = str_replace('//', '/', $new_path);
6122
6123
                // Attempt to update	- tested & working for root	dir
6124
                $new_path = Database::escape_string($new_path);
6125
                $query = "UPDATE $dbTable SET
6126
                            path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
6127
                          WHERE 
6128
                                c_id = $course_id AND 
6129
                                (path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%')";
6130
                Database::query($query);
6131
                break;
6132
        }
6133
    }
6134
6135
    /**
6136
     * This function calculates the resized width and resized heigt
6137
     * according to the source and target widths
6138
     * and heights, height so that no distortions occur
6139
     * parameters.
6140
     *
6141
     * @param $image = the absolute path to the image
0 ignored issues
show
Documentation Bug introduced by
The doc comment = at position 0 could not be parsed: Unknown type name '=' at position 0 in =.
Loading history...
6142
     * @param $target_width = how large do you want your resized image
6143
     * @param $target_height = how large do you want your resized image
6144
     * @param $slideshow (default=0) =
6145
     *      indicates weither we are generating images for a slideshow or not,
6146
     *		this overrides the $_SESSION["image_resizing"] a bit so that a thumbnail
6147
     *	    view is also possible when you choose not to resize the source images
6148
     *
6149
     * @return array
6150
     */
6151
    public static function resizeImageSlideShow(
6152
        $image,
6153
        $target_width,
6154
        $target_height,
6155
        $slideshow = 0
6156
    ) {
6157
        // Modifications by Ivan Tcholakov, 04-MAY-2009.
6158
        $result = [];
6159
        $imageResize = Session::read('image_resizing');
6160
        if ($imageResize == 'resizing' || $slideshow == 1) {
6161
            $new_sizes = api_resize_image($image, $target_width, $target_height);
6162
            $result[] = $new_sizes['height'];
6163
            $result[] = $new_sizes['width'];
6164
        } else {
6165
            $size = api_getimagesize($image);
6166
            $result[] = $size['height'];
6167
            $result[] = $size['width'];
6168
        }
6169
6170
        return $result;
6171
    }
6172
6173
    /**
6174
     * Calculates the total size of a directory by adding the sizes (that
6175
     * are stored in the database) of all files & folders in this directory.
6176
     *
6177
     * @param string $path
6178
     * @param bool   $can_see_invisible
6179
     *
6180
     * @return int Total size
6181
     */
6182
    public static function getTotalFolderSize($path, $can_see_invisible = false)
6183
    {
6184
        $table_itemproperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6185
        $table_document = Database::get_course_table(TABLE_DOCUMENT);
6186
        $tool_document = TOOL_DOCUMENT;
6187
6188
        $course_id = api_get_course_int_id();
6189
        $session_id = api_get_session_id();
6190
        $session_condition = api_get_session_condition(
6191
            $session_id,
6192
            true,
6193
            true,
6194
            'props.session_id'
6195
        );
6196
6197
        if (empty($course_id)) {
6198
            return 0;
6199
        }
6200
6201
        $path = Database::escape_string($path);
6202
        $visibility_rule = ' props.visibility '.($can_see_invisible ? '<> 2' : '= 1');
6203
6204
        $sql = "SELECT SUM(table1.size) FROM (
6205
                SELECT props.ref, size
6206
                FROM $table_itemproperty AS props 
6207
                INNER JOIN $table_document AS docs
6208
                ON (docs.id = props.ref AND docs.c_id = props.c_id)
6209
                WHERE
6210
                    docs.c_id = $course_id AND                    
6211
                    docs.path LIKE '$path/%' AND
6212
                    props.c_id = $course_id AND
6213
                    props.tool = '$tool_document' AND
6214
                    $visibility_rule
6215
                    $session_condition
6216
                GROUP BY ref
6217
            ) as table1";
6218
6219
        $result = Database::query($sql);
6220
        if ($result && Database::num_rows($result) != 0) {
6221
            $row = Database::fetch_row($result);
6222
6223
            return $row[0] == null ? 0 : $row[0];
6224
        } else {
6225
            return 0;
6226
        }
6227
    }
6228
6229
    /**
6230
     * Adds a cloud link to the database.
6231
     *
6232
     * @author - Aquilino Blanco Cores <[email protected]>
6233
     *
6234
     * @param array  $_course
6235
     * @param string $path
6236
     * @param string $url
6237
     * @param string $name
6238
     *
6239
     * @return int id of document or 0 if already exists or there was a problem creating it
6240
     */
6241
    public static function addCloudLink($_course, $path, $url, $name)
6242
    {
6243
        $file_path = $path;
6244
        if (!self::cloudLinkExists($_course, $path, $url)) {
6245
            $doc = self::addDocument($_course, $file_path, 'link', 0, $name, $url);
6246
6247
            return $doc->getId();
6248
        } else {
6249
            return 0;
6250
        }
6251
    }
6252
6253
    /**
6254
     * Deletes a cloud link from the database.
6255
     *
6256
     * @author - Aquilino Blanco Cores <[email protected]>
6257
     *
6258
     * @param array  $courseInfo
6259
     * @param string $documentId
6260
     *
6261
     * @return bool true if success / false if an error occurred
6262
     */
6263
    public static function deleteCloudLink($courseInfo, $documentId)
6264
    {
6265
        if (empty($documentId) || empty($courseInfo)) {
6266
            return false;
6267
        }
6268
6269
        $documentId = (int) $documentId;
6270
        $fileDeletedFromDb = false;
6271
        if (!empty($documentId)) {
6272
            self::deleteDocumentFromDb($documentId, $courseInfo, 0, true);
6273
            // checking
6274
            $table = Database::get_course_table(TABLE_DOCUMENT);
6275
            $courseId = $courseInfo['real_id'];
6276
            echo $sql = "SELECT * FROM $table WHERE id = $documentId AND c_id = $courseId";
6277
            $result = Database::query($sql);
6278
            $exists = Database::num_rows($result) > 0;
6279
            $fileDeletedFromDb = !$exists;
6280
        }
6281
6282
        return $fileDeletedFromDb;
6283
    }
6284
6285
    /**
6286
     * Gets the id of a cloud link with a given path.
6287
     *
6288
     * @author - Aquilino Blanco Cores <[email protected]>
6289
     *
6290
     * @param array  $courseInfo
6291
     * @param string $path
6292
     * @param string $url
6293
     *
6294
     * @return int link's id / false if no link found
6295
     */
6296
    public static function getCloudLinkId($courseInfo, $path, $url)
6297
    {
6298
        $table = Database::get_course_table(TABLE_DOCUMENT);
6299
6300
        if (empty($courseInfo)) {
6301
            return false;
6302
        }
6303
6304
        $courseId = (int) $courseInfo['real_id'];
6305
        $path = Database::escape_string($path);
6306
6307
        if (substr($path, -1) != '/') {
6308
            // Add final slash to path if not present
6309
            $path .= '/';
6310
        }
6311
6312
        if (!empty($courseId) && !empty($path)) {
6313
            $sql = "SELECT id FROM $table 
6314
                    WHERE 
6315
                        c_id = $courseId AND 
6316
                        path LIKE BINARY '$path' AND 
6317
                        comment = '$url' AND 
6318
                        filetype = 'link' 
6319
                    LIMIT 1";
6320
            $result = Database::query($sql);
6321
            if ($result && Database::num_rows($result)) {
6322
                $row = Database::fetch_array($result);
6323
6324
                return intval($row[0]);
6325
            }
6326
        }
6327
6328
        return false;
6329
    }
6330
6331
    /**
6332
     * Checks if a cloud link exists.
6333
     *
6334
     * @author - Aquilino Blanco Cores <[email protected]>
6335
     *
6336
     * @param array  $courseInfo
6337
     * @param string $path
6338
     * @param string $url
6339
     *
6340
     * @return bool true if it exists false in other case
6341
     */
6342
    public static function cloudLinkExists($courseInfo, $path, $url)
6343
    {
6344
        $exists = self::getCloudLinkId($courseInfo, $path, $url);
6345
6346
        return $exists;
6347
    }
6348
6349
    /**
6350
     * Gets the wellformed URLs regular expression in order to use it on forms' verifications.
6351
     *
6352
     * @author Aquilino Blanco Cores <[email protected]>
6353
     *
6354
     * @return string the well formed URLs regular expressions string
6355
     */
6356
    public static function getWellFormedUrlRegex()
6357
    {
6358
        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';
6359
    }
6360
6361
    /**
6362
     * Gets the files hosting sites' whitelist.
6363
     *
6364
     * @author Aquilino Blanco Cores <[email protected]>
6365
     *
6366
     * @return array the sites list
6367
     */
6368
    public static function getFileHostingWhiteList()
6369
    {
6370
        return [
6371
            'asuswebstorage.com',
6372
            'dropbox.com',
6373
            'dropboxusercontent.com',
6374
            'fileserve.com',
6375
            'drive.google.com',
6376
            'docs.google.com',
6377
            'icloud.com',
6378
            'mediafire.com',
6379
            'mega.nz',
6380
            'onedrive.live.com',
6381
            'slideshare.net',
6382
            'scribd.com',
6383
            'wetransfer.com',
6384
            'box.com',
6385
            'livefilestore.com', // OneDrive
6386
        ];
6387
    }
6388
6389
    /**
6390
     * @param int $userId
6391
     *
6392
     * @return array Example [ 0 => ['code' => 'ABC', 'directory' => 'ABC0', 'path' => '/images/gallery/test.png', 'code_path' => 'ABC:/images/gallery/test.png'], 1 => ...]
6393
     */
6394
    public static function getAllDocumentsCreatedByUser($userId)
6395
    {
6396
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6397
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
6398
        $tblCourse = Database::get_main_table(TABLE_MAIN_COURSE);
6399
        $userId = (int) $userId;
6400
6401
        $sql = "SELECT DISTINCT c.code, c.directory, docs.path
6402
                FROM $tblItemProperty AS last
6403
                INNER JOIN $tblDocument AS docs
6404
                ON (
6405
                    docs.id = last.ref AND
6406
                    docs.c_id = last.c_id AND
6407
                    docs.filetype <> 'folder'
6408
                )
6409
                INNER JOIN $tblCourse as c
6410
                ON (
6411
                    docs.c_id = c.id
6412
                )
6413
                WHERE                                
6414
                    last.tool = '".TOOL_DOCUMENT."' AND   
6415
                    last.insert_user_id = $userId AND
6416
                    docs.path NOT LIKE '%_DELETED_%'                     
6417
                ORDER BY c.directory, docs.path
6418
                ";
6419
        $result = Database::query($sql);
6420
6421
        $list = [];
6422
        if (Database::num_rows($result) != 0) {
6423
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6424
                $row['code_path'] = $row['code'].':'.$row['path'];
6425
                $list[] = $row;
6426
            }
6427
        }
6428
6429
        return $list;
6430
    }
6431
6432
    /**
6433
     * @param CDocument  $document
6434
     * @param string     $path
6435
     * @param string     $realPath
6436
     * @param            $content
6437
     * @param int        $visibility
6438
     * @param CGroupInfo $group
6439
     *
6440
     * @return bool|CDocument
6441
     */
6442
    public static function addFileToDocument(CDocument $document, $path, $realPath, $content, $visibility, $group)
6443
    {
6444
        $fileType = $document->getFiletype();
6445
        $resourceNode = $document->getResourceNode();
6446
6447
        if (!$resourceNode) {
6448
            return false;
6449
        }
6450
6451
        $em = Database::getManager();
6452
        $title = $document->getTitle();
6453
6454
        // Only create a ResourceFile and Media if there's a file involved
6455
        if ($fileType === 'file') {
6456
            $mediaManager = Container::$container->get('sonata.media.manager.media');
6457
6458
            $resourceFile = $resourceNode->getResourceFile();
6459
            if (empty($resourceFile)) {
6460
                /** @var \Chamilo\MediaBundle\Entity\Media $media */
6461
                $media = $mediaManager->create();
6462
            } else {
6463
                // If file already exists then we updated it
6464
                $media = $resourceFile->getMedia();
6465
            }
6466
6467
            $media->setName($title);
6468
6469
            $fileName = basename($path);
6470
            $extension = pathinfo($fileName, PATHINFO_EXTENSION);
6471
            $media->setContext('default');
6472
6473
            $provider = 'sonata.media.provider.file';
6474
            $isImage = in_array($extension, ['jpeg', 'jpg', 'gif', 'png']);
6475
            if ($isImage) {
6476
                $provider = 'sonata.media.provider.image';
6477
            }
6478
6479
            error_log($provider);
6480
6481
            $media->setProviderName($provider);
6482
            $media->setEnabled(true);
6483
6484
            if ($content instanceof UploadedFile) {
6485
                $file = $content;
6486
                error_log('1');
6487
                $media->setSize($file->getSize());
6488
            } else {
6489
                // $path points to a file in the directory
6490
                if (file_exists($realPath) && !is_dir($realPath)) {
6491
                    $media->setSize(filesize($realPath));
6492
                    if ($isImage) {
6493
                        $size = getimagesize($realPath);
6494
                        $media->setWidth($size[0]);
6495
                        $media->setHeight($size[1]);
6496
                    }
6497
                    $file = $realPath;
6498
                    error_log('2');
6499
                } else {
6500
                    // We get the content and create a file
6501
                    $handle = tmpfile();
6502
                    fwrite($handle, $content);
6503
                    $file = new \Sonata\MediaBundle\Extra\ApiMediaFile($handle);
6504
                    $file->setMimetype($media->getContentType());
6505
                    error_log($file->getSize());
6506
                    error_log($media->getContentType());
6507
                    error_log('3');
6508
                }
6509
            }
6510
6511
            $media->setBinaryContent($file);
6512
            $mediaManager->save($media, true);
6513
6514
            $resourceFile = $resourceNode->getResourceFile();
6515
            if (empty($resourceFile)) {
6516
                $resourceFile = new ResourceFile();
6517
                $resourceFile->setMedia($media);
6518
            } else {
6519
                $resourceFile->setMedia($media);
6520
            }
6521
            $resourceFile->setName($title);
6522
            $em->persist($resourceFile);
6523
            $resourceNode->setResourceFile($resourceFile);
6524
            $em->persist($resourceNode);
6525
        }
6526
6527
        // By default visibility is published
6528
        // @todo change visibility
6529
        //$newVisibility = ResourceLink::VISIBILITY_PUBLISHED;
6530
        $visibility = (int) $visibility;
6531
        if (empty($visibility)) {
6532
            $visibility = ResourceLink::VISIBILITY_PUBLISHED;
6533
        }
6534
6535
        $link = new ResourceLink();
6536
        $link
6537
            ->setCourse($document->getCourse())
6538
            ->setSession($document->getSession())
6539
            ->setGroup($group)
6540
            //->setUser($toUser)
6541
            ->setResourceNode($resourceNode)
6542
            ->setVisibility($visibility)
6543
        ;
6544
6545
        $rights = [];
6546
        switch ($visibility) {
6547
            case ResourceLink::VISIBILITY_PENDING:
6548
            case ResourceLink::VISIBILITY_DRAFT:
6549
                $editorMask = ResourceNodeVoter::getEditorMask();
6550
                $resourceRight = new ResourceRight();
6551
                $resourceRight
6552
                    ->setMask($editorMask)
6553
                    ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
6554
                ;
6555
                $rights[] = $resourceRight;
6556
6557
                break;
6558
        }
6559
6560
        if (!empty($rights)) {
6561
            foreach ($rights as $right) {
6562
                $link->addResourceRight($right);
6563
            }
6564
        }
6565
6566
        $em->persist($link);
6567
        $em->persist($document);
6568
        $em->flush();
6569
6570
        $documentId = $document->getIid();
6571
        if ($documentId) {
6572
            $table = Database::get_course_table(TABLE_DOCUMENT);
6573
            $sql = "UPDATE $table SET id = iid WHERE iid = $documentId";
6574
            Database::query($sql);
6575
6576
            return $document;
6577
        }
6578
6579
        return false;
6580
    }
6581
6582
    /**
6583
     * Adds a new document to the database.
6584
     *
6585
     * @param array  $courseInfo
6586
     * @param string $path
6587
     * @param string $fileType
6588
     * @param int    $fileSize
6589
     * @param string $title
6590
     * @param string $comment
6591
     * @param int    $readonly
6592
     * @param int    $visibility       see ResourceLink constants
6593
     * @param int    $groupId          group.id
6594
     * @param int    $sessionId        Session ID, if any
6595
     * @param int    $userId           creator user id
6596
     * @param bool   $sendNotification
6597
     * @param string $content
6598
     * @param int    $parentId
6599
     * @param string $realPath
6600
     *
6601
     * @return CDocument|false
6602
     */
6603
    public static function addDocument(
6604
        $courseInfo,
6605
        $path,
6606
        $fileType,
6607
        $fileSize,
6608
        $title,
6609
        $comment = null,
6610
        $readonly = 0,
6611
        $visibility = null,
6612
        $groupId = 0,
6613
        $sessionId = 0,
6614
        $userId = 0,
6615
        $sendNotification = true,
6616
        $content = '',
6617
        $parentId = 0,
6618
        $realPath = ''
6619
    ) {
6620
        $userId = empty($userId) ? api_get_user_id() : $userId;
6621
        if (empty($userId)) {
6622
            return false;
6623
        }
6624
6625
        $userEntity = api_get_user_entity($userId);
6626
        if (empty($userEntity)) {
6627
            return false;
6628
        }
6629
6630
        $courseEntity = api_get_course_entity($courseInfo['real_id']);
6631
        if (empty($courseEntity)) {
6632
            return false;
6633
        }
6634
6635
        $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6636
        $session = api_get_session_entity($sessionId);
6637
        $group = api_get_group_entity($groupId);
6638
        $readonly = (int) $readonly;
6639
6640
        $em = Database::getManager();
6641
        $documentRepo = Container::$container->get('Chamilo\CourseBundle\Repository\CDocumentRepository');
6642
6643
        $parentNode = null;
6644
        if (!empty($parentId)) {
6645
            $parent = $documentRepo->find($parentId);
6646
            if ($parent) {
6647
                $parentNode = $parent->getResourceNode();
6648
            }
6649
        }
6650
6651
        $criteria = ['path' => $path, 'course' => $courseEntity];
6652
        $document = $documentRepo->findOneBy($criteria);
6653
6654
        // Document already exists
6655
        if ($document) {
6656
            return false;
6657
        }
6658
6659
        $document = new CDocument();
6660
        $document
6661
            ->setCourse($courseEntity)
6662
            ->setPath($path)
6663
            ->setFiletype($fileType)
6664
            ->setSize($fileSize)
6665
            ->setTitle($title)
6666
            ->setComment($comment)
6667
            ->setReadonly($readonly)
6668
            ->setSession($session)
6669
        ;
6670
6671
        $em->persist($document);
6672
        $em->flush();
6673
6674
        $resourceNode = $documentRepo->addResourceNode($document, $userEntity);
6675
        $resourceNode->setParent($parentNode);
6676
        $document->setResourceNode($resourceNode);
6677
6678
        $document = self::addFileToDocument($document, $path, $realPath, $content, $visibility, $group);
6679
6680
        if ($document) {
6681
            $allowNotification = api_get_configuration_value('send_notification_when_document_added');
6682
            if ($sendNotification && $allowNotification) {
6683
                $courseTitle = $courseInfo['title'];
6684
                if (!empty($sessionId)) {
6685
                    $sessionInfo = api_get_session_info($sessionId);
6686
                    $courseTitle .= ' ( '.$sessionInfo['name'].') ';
6687
                }
6688
6689
                $url = api_get_path(WEB_CODE_PATH).
6690
                    'document/showinframes.php?cidReq='.$courseInfo['code'].'&id_session='.$sessionId.'&id='.$document->getId();
6691
                $link = Display::url(basename($title), $url, ['target' => '_blank']);
6692
                $userInfo = api_get_user_info($userId);
6693
6694
                $message = sprintf(
6695
                    get_lang('DocumentXHasBeenAddedToDocumentInYourCourseXByUserX'),
6696
                    $link,
6697
                    $courseTitle,
6698
                    $userInfo['complete_name']
6699
                );
6700
                $subject = sprintf(get_lang('NewDocumentAddedToCourseX'), $courseTitle);
6701
                MessageManager::sendMessageToAllUsersInCourse($subject, $message, $courseInfo, $sessionId);
6702
            }
6703
6704
            return $document;
6705
        }
6706
6707
        return false;
6708
    }
6709
6710
    /**
6711
     * Parse file information into a link.
6712
     *
6713
     * @param array  $userInfo        Current user info
6714
     * @param array  $course_info
6715
     * @param int    $session_id
6716
     * @param array  $resource
6717
     * @param int    $lp_id
6718
     * @param bool   $add_move_button
6719
     * @param string $target
6720
     * @param string $overwrite_url
6721
     *
6722
     * @return string|null
6723
     */
6724
    private static function parseFile(
6725
        $userInfo,
6726
        $course_info,
6727
        $session_id,
6728
        $resource,
6729
        $lp_id,
6730
        $add_move_button,
6731
        $target,
6732
        $overwrite_url
6733
    ) {
6734
        $img_sys_path = api_get_path(SYS_CODE_PATH).'img/';
6735
        $web_code_path = api_get_path(WEB_CODE_PATH);
6736
6737
        $documentId = $resource['id'];
6738
        $path = $resource['path'];
6739
6740
        if (empty($path)) {
6741
            $num = 0;
6742
        } else {
6743
            $num = substr_count($path, '/') - 1;
6744
        }
6745
6746
        // It's a file.
6747
        $icon = choose_image($path);
6748
        $position = strrpos($icon, '.');
6749
        $icon = substr($icon, 0, $position).'_small.gif';
6750
        $my_file_title = $resource['title'];
6751
        $visibility = $resource['visibility'];
6752
6753
        // If title is empty we try to use the path
6754
        if (empty($my_file_title)) {
6755
            $my_file_title = basename($path);
6756
        }
6757
6758
        // Show the "image name" not the filename of the image.
6759
        if ($lp_id) {
6760
            // LP URL
6761
            $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;
6762
        } else {
6763
            // Direct document URL
6764
            $url = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6765
        }
6766
6767
        if (!empty($overwrite_url)) {
6768
            $overwrite_url = Security::remove_XSS($overwrite_url);
6769
            $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId;
6770
        }
6771
6772
        $img = Display::returnIconPath($icon);
6773
        if (!file_exists($img_sys_path.$icon)) {
6774
            $img = Display::returnIconPath('default_small.png');
6775
        }
6776
6777
        $link = Display::url(
6778
            '<img alt="" src="'.$img.'" title="" />&nbsp;'.$my_file_title,
6779
            $url,
6780
            ['target' => $target, 'class' => 'moved']
6781
        );
6782
6783
        $directUrl = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6784
        $link .= '&nbsp;'.Display::url(
6785
            Display::return_icon('preview_view.png', get_lang('Preview')),
6786
            $directUrl,
6787
            ['target' => '_blank']
6788
        );
6789
6790
        $visibilityClass = null;
6791
        if ($visibility == 0) {
6792
            $visibilityClass = ' text-muted ';
6793
        }
6794
        $return = null;
6795
6796
        if ($lp_id == false) {
6797
            $return .= '<li class="doc_resource '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6798
        } else {
6799
            $return .= '<li class="doc_resource lp_resource_element '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6800
        }
6801
6802
        $return .= '<div class="item_data" style="margin-left:'.($num * 5).'px;margin-right:5px;">';
6803
        if ($add_move_button) {
6804
            $return .= '<a class="moved" href="#">';
6805
            $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), [], ICON_SIZE_TINY);
6806
            $return .= '</a> ';
6807
        }
6808
        $return .= $link;
6809
        $sessionStar = api_get_session_image($resource['session_id'], $userInfo['status']);
6810
        $return .= $sessionStar;
6811
6812
        $return .= '</div></li>';
6813
6814
        return $return;
6815
    }
6816
6817
    /**
6818
     * @param int   $folderId
6819
     * @param array $resource
6820
     * @param int   $lp_id
6821
     *
6822
     * @return string|null
6823
     */
6824
    private static function parseFolder($folderId, $resource, $lp_id)
6825
    {
6826
        $title = isset($resource['title']) ? $resource['title'] : null;
6827
        $path = isset($resource['path']) ? $resource['path'] : null;
6828
6829
        if (empty($path)) {
6830
            $num = 0;
6831
        } else {
6832
            $num = substr_count($path, '/');
6833
        }
6834
6835
        // It's a folder.
6836
        //hide some folders
6837
        if (in_array(
6838
            $path,
6839
            ['shared_folder', 'chat_files', 'HotPotatoes_files', 'css', 'certificates']
6840
        )) {
6841
            return null;
6842
        } elseif (preg_match('/_groupdocs/', $path)) {
6843
            return null;
6844
        } elseif (preg_match('/sf_user_/', $path)) {
6845
            return null;
6846
        } elseif (preg_match('/shared_folder_session_/', $path)) {
6847
            return null;
6848
        }
6849
6850
        //$onclick = '';
6851
        // if in LP, hidden folder are displayed in grey
6852
        $folder_class_hidden = '';
6853
        if ($lp_id) {
6854
            if (isset($resource['visible']) && $resource['visible'] == 0) {
6855
                $folder_class_hidden = ' doc_folder_hidden'; // in base.css
6856
            }
6857
        }
6858
        $onclick = 'onclick="javascript: testResources(\'res_'.$resource['id'].'\',\'img_'.$resource['id'].'\')"';
6859
        $return = null;
6860
6861
        if (empty($path)) {
6862
            $return = '<ul class="lp_resource">';
6863
        }
6864
6865
        $return .= '<li class="doc_folder '.$folder_class_hidden.'" id="doc_id_'.$resource['id'].'"  style="margin-left:'.($num * 18).'px; ">';
6866
6867
        $image = Display::returnIconPath('nolines_plus.gif');
6868
        if (empty($path)) {
6869
            $image = Display::returnIconPath('nolines_minus.gif');
6870
        }
6871
        $return .= '<img style="cursor: pointer;" src="'.$image.'" align="absmiddle" id="img_'.$resource['id'].'" '.$onclick.'>';
6872
        $return .= Display::return_icon('lp_folder.png').'&nbsp;';
6873
        $return .= '<span '.$onclick.' style="cursor: pointer;" >'.$title.'</span>';
6874
        $return .= '</li>';
6875
6876
        if (empty($path)) {
6877
            if ($folderId == false) {
6878
                $return .= '<div id="res_'.$resource['id'].'" >';
6879
            } else {
6880
                $return .= '<div id="res_'.$resource['id'].'" style="display: none;" >';
6881
            }
6882
        }
6883
6884
        return $return;
6885
    }
6886
6887
    /**
6888
     * Get the button to edit document.
6889
     *
6890
     * @param bool   $isReadOnly
6891
     * @param array  $documentData
6892
     * @param string $extension
6893
     * @param bool   $isCertificateMode
6894
     *
6895
     * @return string
6896
     */
6897
    private static function getButtonEdit($isReadOnly, array $documentData, $extension, $isCertificateMode)
6898
    {
6899
        $extension = strtolower($extension);
6900
        $iconEn = Display::return_icon('edit.png', get_lang('Modify'));
6901
        $iconDis = Display::return_icon('edit_na.png', get_lang('Modify'));
6902
        $courseParams = api_get_cidreq();
6903
        $webOdfExtensionList = self::get_web_odf_extension_list();
6904
        $path = $documentData['path'];
6905
        $documentId = $documentData['id'];
6906
6907
        if ($isReadOnly) {
6908
            if (!api_is_course_admin() && !api_is_platform_admin()) {
6909
                return $iconDis;
6910
            }
6911
6912
            if (
6913
                $extension == 'svg' && api_browser_support('svg') &&
6914
                api_get_setting('enabled_support_svg') == 'true'
6915
            ) {
6916
                return Display::url($iconEn, "edit_draw.php?$courseParams&id=$documentId");
6917
            }
6918
6919
            if (
6920
                in_array($extension, $webOdfExtensionList) &&
6921
                api_get_configuration_value('enabled_support_odf') === true
6922
            ) {
6923
                return Display::url($iconEn, "edit_odf.php?$courseParams&id=$documentId");
6924
            }
6925
6926
            if (
6927
                in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6928
                    api_get_setting('enabled_support_pixlr') == 'true'
6929
            ) {
6930
                return Display::url($iconEn, "edit_paint.php?$courseParams&id=$documentId");
6931
            }
6932
6933
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$documentId");
6934
        }
6935
6936
        if (in_array($path, self::get_system_folders())) {
6937
            return $iconDis;
6938
        }
6939
6940
        if ($isCertificateMode) {
6941
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$documentId&curdirpath=/certificates");
6942
        }
6943
6944
        $sessionId = api_get_session_id();
6945
6946
        if ($sessionId && $documentData['session_id'] != $sessionId) {
6947
            return $iconDis;
6948
        }
6949
6950
        if (
6951
            $extension == 'svg' && api_browser_support('svg') &&
6952
            api_get_setting('enabled_support_svg') == 'true'
6953
        ) {
6954
            return Display::url($iconEn, "edit_draw.php?$courseParams&id=$documentId");
6955
        }
6956
6957
        if (
6958
            in_array($extension, $webOdfExtensionList) &&
6959
            api_get_configuration_value('enabled_support_odf') === true
6960
        ) {
6961
            return Display::url($iconEn, "edit_odf.php?$courseParams&id=$documentId");
6962
        }
6963
6964
        if (
6965
            in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6966
                api_get_setting('enabled_support_pixlr') == 'true'
6967
        ) {
6968
            return Display::url($iconEn, "edit_paint.php?$courseParams&id=$documentId");
6969
        }
6970
6971
        return Display::url($iconEn, "edit_document.php?$courseParams&id=$documentId");
6972
    }
6973
6974
    /**
6975
     * Get the button to move document.
6976
     *
6977
     * @param bool  $isReadOnly
6978
     * @param array $documentData
6979
     * @param bool  $isCertificateMode
6980
     * @param int   $parentId
6981
     *
6982
     * @return string
6983
     */
6984
    private static function getButtonMove($isReadOnly, array $documentData, $isCertificateMode, $parentId)
6985
    {
6986
        $iconEn = Display::return_icon('move.png', get_lang('Move'));
6987
        $iconDis = Display::return_icon('move_na.png', get_lang('Move'));
6988
6989
        if ($isReadOnly) {
6990
            return $iconDis;
6991
        }
6992
6993
        $path = $documentData['path'];
6994
        $document_id = $documentData['id'];
6995
        $sessionId = api_get_session_id();
6996
        $courseParams = api_get_cidreq();
6997
6998
        if ($isCertificateMode || in_array($path, self::get_system_folders())) {
6999
            return $iconDis;
7000
        }
7001
7002
        if ($sessionId) {
7003
            if ($documentData['session_id'] != $sessionId) {
7004
                return $iconDis;
7005
            }
7006
        }
7007
7008
        $urlMoveParams = http_build_query(['id' => $parentId, 'move' => $document_id]);
7009
7010
        return Display::url(
7011
            $iconEn,
7012
            api_get_self()."?$courseParams&$urlMoveParams"
7013
        );
7014
    }
7015
7016
    /**
7017
     * Get the button to set visibility to document.
7018
     *
7019
     * @param bool  $isReadOnly
7020
     * @param int   $visibility
7021
     * @param array $documentData
7022
     * @param bool  $isCertificateMode
7023
     * @param int   $parentId
7024
     *
7025
     * @return string|null
7026
     */
7027
    private static function getButtonVisibility(
7028
        $isReadOnly,
7029
        $visibility,
7030
        array $documentData,
7031
        $isCertificateMode,
7032
        $parentId
7033
    ) {
7034
        $visibility_icon = $visibility == 0 ? 'invisible' : 'visible';
7035
        $visibility_command = $visibility == 0 ? 'set_visible' : 'set_invisible';
7036
        $courseParams = api_get_cidreq();
7037
7038
        if ($isReadOnly) {
7039
            if (api_is_allowed_to_edit() || api_is_platform_admin()) {
7040
                return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
7041
            }
7042
7043
            return null;
7044
        }
7045
7046
        if ($isCertificateMode) {
7047
            return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
7048
        }
7049
7050
        if (api_is_allowed_to_edit() || api_is_platform_admin()) {
7051
            $tip_visibility = $visibility_icon == 'invisible' ? get_lang('Show') : get_lang('Hide');
7052
7053
            return Display::url(
7054
                Display::return_icon($visibility_icon.'.png', $tip_visibility),
7055
                api_get_self()."?$courseParams&id=$parentId&$visibility_command={$documentData['id']}"
7056
            );
7057
        }
7058
7059
        return null;
7060
    }
7061
7062
    /**
7063
     * GEt the button to delete a document.
7064
     *
7065
     * @param bool   $isReadOnly
7066
     * @param array  $documentData
7067
     * @param bool   $isCertificateMode
7068
     * @param string $curDirPath
7069
     * @param int    $parentId
7070
     *
7071
     * @return string
7072
     */
7073
    private static function getButtonDelete(
7074
        $isReadOnly,
7075
        array $documentData,
7076
        $isCertificateMode,
7077
        $curDirPath,
7078
        $parentId
7079
    ) {
7080
        $iconEn = Display::return_icon('delete.png', get_lang('Delete'));
7081
        $iconDis = Display::return_icon('delete_na.png', get_lang('ThisFolderCannotBeDeleted'));
7082
        $path = $documentData['path'];
7083
        $id = $documentData['id'];
7084
        $courseParams = api_get_cidreq();
7085
7086
        if ($isReadOnly) {
7087
            return $iconDis;
7088
        }
7089
7090
        if (in_array($path, self::get_system_folders())) {
7091
            return $iconDis;
7092
        }
7093
7094
        $titleToShow = addslashes(basename($documentData['title']));
7095
        $urlDeleteParams = http_build_query([
7096
            'curdirpath' => $curDirPath,
7097
            'action' => 'delete_item',
7098
            'id' => $parentId,
7099
            'deleteid' => $documentData['id'],
7100
        ]);
7101
7102
        $btn = Display::url(
7103
            $iconEn,
7104
            api_get_self()."?$courseParams&$urlDeleteParams",
7105
            [
7106
                'title' => get_lang('Do you want to delete the file?').': '.$titleToShow,
7107
                'class' => 'delete-swal',
7108
            ]
7109
        );
7110
7111
        if (
7112
            isset($_GET['curdirpath']) &&
7113
            $_GET['curdirpath'] == '/certificates' &&
7114
            self::get_default_certificate_id(api_get_course_int_id()) == $id
7115
        ) {
7116
            return $btn;
7117
        }
7118
7119
        if ($isCertificateMode) {
7120
            return $btn;
7121
        }
7122
7123
        $sessionId = api_get_session_id();
7124
7125
        if ($sessionId) {
7126
            if ($documentData['session_id'] != $sessionId) {
7127
                return $iconDis;
7128
            }
7129
        }
7130
7131
        return $btn;
7132
    }
7133
}
7134