Passed
Push — 1.11.x ( d3c839...bcb967 )
by Julito
09:33
created

DocumentManager   F

Complexity

Total Complexity 983

Size/Duplication

Total Lines 7003
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 3644
dl 0
loc 7003
rs 0.8
c 4
b 0
f 0
wmc 983

104 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A get_course_quota() 0 20 5
B file_get_mime_type() 0 214 4
B smartReadFile() 0 54 11
F parseFolder() 0 61 15
A getButtonMove() 0 29 6
A getSessionFolderFilters() 0 15 3
A is_folder() 0 13 2
A deleteDocumentFromDb() 0 48 4
A delete_document_from_search_engine() 0 20 3
F delete_document() 0 192 29
F file_send_for_download() 0 139 34
F is_visible_by_id() 0 118 25
A attach_gradebook_certificate() 0 18 4
A set_document_as_template() 0 21 1
A get_default_certificate_id() 0 26 5
B create_directory_certificate_in_course() 0 55 5
D replaceUrlWithNewCourseCode() 0 160 22
A replace_user_info_into_html() 0 51 4
A get_document_id_of_directory_certificate() 0 10 1
D parse_HTML_attributes() 0 82 21
B get_document_id() 0 34 6
B is_visible() 0 76 7
A remove_attach_certificate() 0 23 6
A unset_document_as_template() 0 26 1
F get_resources_from_source_html() 0 364 66
C get_document_data_by_id() 0 97 16
A is_certificate_mode() 0 11 5
F get_all_info_to_certificate() 0 159 13
A generateAudioJavascript() 0 12 1
A generateAudioPreview() 0 7 1
A export_to_pdf() 0 34 4
A enough_space() 0 10 3
A generateMediaPreview() 0 18 3
D get_text_content() 0 72 20
A displaySimpleQuota() 0 10 1
B documents_total_space() 0 43 6
C upload_document() 0 109 16
C check_readonly() 0 84 16
F getAllDocumentData() 0 184 33
F get_all_document_folders() 0 202 24
A updateVisibilityFromAllSessions() 0 18 3
A getDeletedDocument() 0 26 3
A get_titles_of_path() 0 31 4
A undoFixDocumentName() 0 19 3
F create_document_link() 0 314 94
F getJodconverterExtensionList() 0 111 19
D getButtonEdit() 0 75 22
A getDocumentDefaultVisibility() 0 22 6
B write_resources_tree() 0 58 8
A downloadDeletedDocument() 0 9 3
D build_document_icon_tag() 0 96 24
A is_my_shared_folder() 0 14 3
B getButtonDelete() 0 61 9
A cloudLinkExists() 0 5 1
A removeGeneratedAudioTempFile() 0 6 3
D isBrowserViewable() 0 62 24
F build_edit_icons() 0 120 22
A isBasicCourseFolder() 0 6 1
A addFileToDocumentTool() 0 52 3
A generateAudioTempFile() 0 37 5
D build_move_to_selector() 0 86 29
A getDocumentByPathInCourse() 0 12 2
A createDefaultAudioFolder() 0 26 3
A renameDocument() 0 15 1
A updateDbInfo() 0 31 4
A convertWavToMp3() 0 23 6
B generateDefaultCertificate() 0 92 9
A getUniqueFileName() 0 17 2
A documentExists() 0 43 3
A getDeletedDocuments() 0 20 2
A folderExists() 0 40 3
A getFileHostingWhiteList() 0 19 1
A get_system_folders() 0 12 1
A is_any_user_shared_folder() 0 10 3
A addSuffixToFileName() 0 17 4
A resizeImageSlideShow() 0 20 3
D parseFile() 0 95 10
A purgeDocument() 0 14 2
F index_document() 0 220 31
A getFormatTypeListConvertor() 0 11 3
A getDocumentSuffix() 0 8 3
A deleteDocumentsFromSession() 0 54 5
A downloadAllDeletedDocument() 0 25 4
A getWellFormedUrlRegex() 0 3 1
A getProtectedFolderFromStudent() 0 8 1
A get_web_odf_extension_list() 0 3 1
A getAllDocumentsCreatedByUser() 0 36 3
A is_shared_folder() 0 10 3
B getButtonVisibility() 0 33 10
C check_visibility_tree() 0 67 14
B getTotalFolderSize() 0 44 6
F get_document_preview() 0 258 35
A deleteCloudLink() 0 20 4
A create_dir_form() 0 12 1
B addAndConvertWavToMp3() 0 49 8
B getCloudLinkId() 0 33 7
C build_directory_selector() 0 92 16
A purgeDocuments() 0 5 2
B is_folder_to_avoid() 0 49 10
A addCloudLink() 0 27 3
B createUserSharedFolder() 0 72 6
A fixDocumentName() 0 14 3
A searchKeyword() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like DocumentManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DocumentManager, and based on these observations, apply Extract Interface, too.

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