Passed
Push — master ( 83aef6...b86f20 )
by Julito
10:30
created

DocumentManager::create_dir_form()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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