Passed
Push — master ( 58a83e...68c421 )
by Julito
10:15
created

DocumentManager::is_visible_by_id()   D

Complexity

Conditions 29
Paths 97

Size

Total Lines 139
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
eloc 72
nc 97
nop 6
dl 0
loc 139
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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