Passed
Push — master ( df67a3...c6e3ba )
by Julito
08:42
created

DocumentManager::get_text_content()   D

Complexity

Conditions 20
Paths 72

Size

Total Lines 72
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 52
nc 72
nop 2
dl 0
loc 72
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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