Completed
Push — master ( 88715c...d7c14e )
by Julito
09:34
created

DocumentManager::check_visibility_tree()   C

Complexity

Conditions 13
Paths 16

Size

Total Lines 68
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 38
nc 16
nop 6
dl 0
loc 68
rs 6.6166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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