Passed
Push — master ( e6c349...49aad9 )
by Julito
10:08
created

DocumentManager::folderExists()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 40
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

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