Passed
Push — master ( c7bba1...5403d9 )
by Julito
17:42 queued 08:42
created

DocumentManager::readNanogongFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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