Passed
Push — master ( c30c5e...40a9ec )
by Yannick
09:04
created

DocumentManager::smartReadFile()   B

Complexity

Conditions 11
Paths 34

Size

Total Lines 52
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 11
eloc 35
c 3
b 0
f 0
nc 34
nop 3
dl 0
loc 52
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Resource\ResourceFile;
5
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
6
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
7
use Chamilo\CoreBundle\Framework\Container;
8
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
9
use Chamilo\CourseBundle\Entity\CDocument;
10
use Chamilo\UserBundle\Entity\User;
11
use ChamiloSession as Session;
12
use Symfony\Component\HttpFoundation\File\UploadedFile;
13
14
/**
15
 *  Class DocumentManager
16
 *  This is the document library for Chamilo.
17
 *  It is / will be used to provide a service layer to all document-using tools.
18
 *  and eliminate code duplication fro group documents, scorm documents, main documents.
19
 *  Include/require it in your code to use its functionality.
20
 *
21
 * @package chamilo.library
22
 */
23
class DocumentManager
24
{
25
    /**
26
     * Construct.
27
     */
28
    private function __construct()
29
    {
30
    }
31
32
    /**
33
     * @param string $course_code
34
     *
35
     * @return int the document folder quota for the current course in bytes
36
     *             or the default quota
37
     */
38
    public static function get_course_quota($course_code = null)
39
    {
40
        if (empty($course_code)) {
41
            $course_info = api_get_course_info();
42
        } else {
43
            $course_info = api_get_course_info($course_code);
44
        }
45
46
        $course_quota = null;
47
        if (empty($course_info)) {
48
            return DEFAULT_DOCUMENT_QUOTA;
49
        } else {
50
            $course_quota = $course_info['disk_quota'];
51
        }
52
        if (is_null($course_quota) || empty($course_quota)) {
53
            // Course table entry for quota was null, then use default value
54
            $course_quota = DEFAULT_DOCUMENT_QUOTA;
55
        }
56
57
        return $course_quota;
58
    }
59
60
    /**
61
     * Get the content type of a file by checking the extension
62
     * We could use mime_content_type() with php-versions > 4.3,
63
     * but this doesn't work as it should on Windows installations.
64
     *
65
     * @param string $filename or boolean TRUE to return complete array
66
     *
67
     * @author ? first version
68
     * @author Bert Vanderkimpen
69
     *
70
     * @return string
71
     */
72
    public static function file_get_mime_type($filename)
73
    {
74
        // All MIME types in an array (from 1.6, this is the authorative source)
75
        // Please, keep this alphabetical if you add something to this list!
76
        $mimeTypes = [
77
            'ai' => 'application/postscript',
78
            'aif' => 'audio/x-aiff',
79
            'aifc' => 'audio/x-aiff',
80
            'aiff' => 'audio/x-aiff',
81
            'asf' => 'video/x-ms-asf',
82
            'asc' => 'text/plain',
83
            'au' => 'audio/basic',
84
            'avi' => 'video/x-msvideo',
85
            'bcpio' => 'application/x-bcpio',
86
            'bin' => 'application/octet-stream',
87
            'bmp' => 'image/bmp',
88
            'cdf' => 'application/x-netcdf',
89
            'class' => 'application/octet-stream',
90
            'cpio' => 'application/x-cpio',
91
            'cpt' => 'application/mac-compactpro',
92
            'csh' => 'application/x-csh',
93
            'css' => 'text/css',
94
            'dcr' => 'application/x-director',
95
            'dir' => 'application/x-director',
96
            'djv' => 'image/vnd.djvu',
97
            'djvu' => 'image/vnd.djvu',
98
            'dll' => 'application/octet-stream',
99
            'dmg' => 'application/x-diskcopy',
100
            'dms' => 'application/octet-stream',
101
            'doc' => 'application/msword',
102
            'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
103
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
104
            'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
105
            'dvi' => 'application/x-dvi',
106
            'dwg' => 'application/vnd.dwg',
107
            'dwf' => 'application/vnd.dwf',
108
            'dxf' => 'application/vnd.dxf',
109
            'dxr' => 'application/x-director',
110
            'eps' => 'application/postscript',
111
            'epub' => 'application/epub+zip',
112
            'etx' => 'text/x-setext',
113
            'exe' => 'application/octet-stream',
114
            'ez' => 'application/andrew-inset',
115
            'flv' => 'video/flv',
116
            'gif' => 'image/gif',
117
            'gtar' => 'application/x-gtar',
118
            'gz' => 'application/x-gzip',
119
            'hdf' => 'application/x-hdf',
120
            'hqx' => 'application/mac-binhex40',
121
            'htm' => 'text/html',
122
            'html' => 'text/html',
123
            'ice' => 'x-conference-xcooltalk',
124
            'ief' => 'image/ief',
125
            'iges' => 'model/iges',
126
            'igs' => 'model/iges',
127
            'jar' => 'application/java-archiver',
128
            'jpe' => 'image/jpeg',
129
            'jpeg' => 'image/jpeg',
130
            'jpg' => 'image/jpeg',
131
            'js' => 'application/x-javascript',
132
            'kar' => 'audio/midi',
133
            'lam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
134
            'latex' => 'application/x-latex',
135
            'lha' => 'application/octet-stream',
136
            'log' => 'text/plain',
137
            'lzh' => 'application/octet-stream',
138
            'm1a' => 'audio/mpeg',
139
            'm2a' => 'audio/mpeg',
140
            'm3u' => 'audio/x-mpegurl',
141
            'man' => 'application/x-troff-man',
142
            'me' => 'application/x-troff-me',
143
            'mesh' => 'model/mesh',
144
            'mid' => 'audio/midi',
145
            'midi' => 'audio/midi',
146
            'mov' => 'video/quicktime',
147
            'movie' => 'video/x-sgi-movie',
148
            'mp2' => 'audio/mpeg',
149
            'mp3' => 'audio/mpeg',
150
            'mp4' => 'video/mp4',
151
            'mpa' => 'audio/mpeg',
152
            'mpe' => 'video/mpeg',
153
            'mpeg' => 'video/mpeg',
154
            'mpg' => 'video/mpeg',
155
            'mpga' => 'audio/mpeg',
156
            'ms' => 'application/x-troff-ms',
157
            'msh' => 'model/mesh',
158
            'mxu' => 'video/vnd.mpegurl',
159
            'nc' => 'application/x-netcdf',
160
            'oda' => 'application/oda',
161
            'oga' => 'audio/ogg',
162
            'ogg' => 'application/ogg',
163
            'ogx' => 'application/ogg',
164
            'ogv' => 'video/ogg',
165
            'pbm' => 'image/x-portable-bitmap',
166
            'pct' => 'image/pict',
167
            'pdb' => 'chemical/x-pdb',
168
            'pdf' => 'application/pdf',
169
            'pgm' => 'image/x-portable-graymap',
170
            'pgn' => 'application/x-chess-pgn',
171
            'pict' => 'image/pict',
172
            'png' => 'image/png',
173
            'pnm' => 'image/x-portable-anymap',
174
            'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
175
            'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
176
            'pps' => 'application/vnd.ms-powerpoint',
177
            'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
178
            'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
179
            'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
180
            'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
181
            'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
182
            'ppm' => 'image/x-portable-pixmap',
183
            'ppt' => 'application/vnd.ms-powerpoint',
184
            'pps' => 'application/vnd.ms-powerpoint',
185
            'ps' => 'application/postscript',
186
            'qt' => 'video/quicktime',
187
            'ra' => 'audio/x-realaudio',
188
            'ram' => 'audio/x-pn-realaudio',
189
            'rar' => 'image/x-rar-compressed',
190
            'ras' => 'image/x-cmu-raster',
191
            'rgb' => 'image/x-rgb',
192
            'rm' => 'audio/x-pn-realaudio',
193
            'roff' => 'application/x-troff',
194
            'rpm' => 'audio/x-pn-realaudio-plugin',
195
            'rtf' => 'text/rtf',
196
            'rtx' => 'text/richtext',
197
            'sgm' => 'text/sgml',
198
            'sgml' => 'text/sgml',
199
            'sh' => 'application/x-sh',
200
            'shar' => 'application/x-shar',
201
            'silo' => 'model/mesh',
202
            'sib' => 'application/X-Sibelius-Score',
203
            'sit' => 'application/x-stuffit',
204
            'skd' => 'application/x-koan',
205
            'skm' => 'application/x-koan',
206
            'skp' => 'application/x-koan',
207
            'skt' => 'application/x-koan',
208
            'smi' => 'application/smil',
209
            'smil' => 'application/smil',
210
            'snd' => 'audio/basic',
211
            'so' => 'application/octet-stream',
212
            'spl' => 'application/x-futuresplash',
213
            'src' => 'application/x-wais-source',
214
            'sv4cpio' => 'application/x-sv4cpio',
215
            'sv4crc' => 'application/x-sv4crc',
216
            'svf' => 'application/vnd.svf',
217
            'svg' => 'image/svg+xml',
218
            //'svgz' => 'image/svg+xml',
219
            'swf' => 'application/x-shockwave-flash',
220
            'sxc' => 'application/vnd.sun.xml.calc',
221
            'sxi' => 'application/vnd.sun.xml.impress',
222
            'sxw' => 'application/vnd.sun.xml.writer',
223
            't' => 'application/x-troff',
224
            'tar' => 'application/x-tar',
225
            'tcl' => 'application/x-tcl',
226
            'tex' => 'application/x-tex',
227
            'texi' => 'application/x-texinfo',
228
            'texinfo' => 'application/x-texinfo',
229
            'tga' => 'image/x-targa',
230
            'tif' => 'image/tif',
231
            'tiff' => 'image/tiff',
232
            'tr' => 'application/x-troff',
233
            'tsv' => 'text/tab-seperated-values',
234
            'txt' => 'text/plain',
235
            'ustar' => 'application/x-ustar',
236
            'vcd' => 'application/x-cdlink',
237
            'vrml' => 'model/vrml',
238
            'wav' => 'audio/x-wav',
239
            'wbmp' => 'image/vnd.wap.wbmp',
240
            'wbxml' => 'application/vnd.wap.wbxml',
241
            'webp' => 'image/webp',
242
            'wml' => 'text/vnd.wap.wml',
243
            'wmlc' => 'application/vnd.wap.wmlc',
244
            'wmls' => 'text/vnd.wap.wmlscript',
245
            'wmlsc' => 'application/vnd.wap.wmlscriptc',
246
            'wma' => 'audio/x-ms-wma',
247
            'wmv' => 'video/x-ms-wmv',
248
            'wrl' => 'model/vrml',
249
            'xbm' => 'image/x-xbitmap',
250
            'xht' => 'application/xhtml+xml',
251
            'xhtml' => 'application/xhtml+xml',
252
            'xls' => 'application/vnd.ms-excel',
253
            'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
254
            'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
255
            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
256
            'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
257
            'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
258
            'xml' => 'text/xml',
259
            'xpm' => 'image/x-xpixmap',
260
            'xsl' => 'text/xml',
261
            'xwd' => 'image/x-windowdump',
262
            'xyz' => 'chemical/x-xyz',
263
            'zip' => 'application/zip',
264
        ];
265
266
        if ($filename === true) {
267
            return $mimeTypes;
268
        }
269
270
        //get the extension of the file
271
        $extension = explode('.', $filename);
272
273
        //$filename will be an array if a . was found
274
        if (is_array($extension)) {
275
            $extension = strtolower($extension[count($extension) - 1]);
276
        } else {
277
            //file without extension
278
            $extension = 'empty';
279
        }
280
281
        //if the extension is found, return the content type
282
        if (isset($mimeTypes[$extension])) {
283
            return $mimeTypes[$extension];
284
        }
285
286
        return 'application/octet-stream';
287
    }
288
	 /**
289
     * This function smart streams a file to the client using HTTP headers
290
     *
291
     * @param string $fullFilename The full path of the file to be sent
292
     * @param string $filename     The name of the file as shown to the client
293
     * @param string $contentType  The MIME type of the file
294
     *
295
     * @return bool false if file doesn't exist, true if stream succeeded
296
     */
297
	public static function smartReadFile($fullFilename, $filename, $contentType = 'application/octet-stream')
298
	{
299
        if (!file_exists($fullFilename)) {
300
            header ("HTTP/1.1 404 Not Found");
301
            return false;
302
        }
303
304
        $size = filesize($fullFilename);
305
        $time = date('r', filemtime($fullFilename));
306
        
307
        $fm = @fopen($fullFilename, 'rb');
308
        if (!$fm) {
0 ignored issues
show
introduced by
$fm is of type false|resource, thus it always evaluated to false.
Loading history...
309
            header ("HTTP/1.1 505 Internal server error");
310
            return false;
311
        }
312
        
313
        $begin = 0;
314
        $end = $size - 1;
315
        
316
        if (isset($_SERVER['HTTP_RANGE'])) {
317
            if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
318
                $begin = intval($matches[1]);
319
                if (!empty($matches[2])) {
320
                    $end = intval($matches[2]);
321
                }
322
            }
323
        }
324
    
325
        if (isset($_SERVER['HTTP_RANGE'])) {
326
            header('HTTP/1.1 206 Partial Content');
327
        } else {
328
            header('HTTP/1.1 200 OK');
329
        }
330
        
331
        header("Content-Type: $contentType"); 
332
        header('Cache-Control: public, must-revalidate, max-age=0');
333
        header('Pragma: no-cache');  
334
        header('Accept-Ranges: bytes');
335
        header('Content-Length:' . (($end - $begin) + 1));
336
        if (isset($_SERVER['HTTP_RANGE'])) {
337
            header("Content-Range: bytes $begin-$end/$size");
338
        }
339
        header("Content-Disposition: inline; filename=$filename");
340
        header("Content-Transfer-Encoding: binary");
341
        header("Last-Modified: $time");
342
        
343
        $cur = $begin;
344
        fseek($fm, $begin, 0);
345
        
346
        while(!feof($fm) && $cur <= $end && (connection_status() == 0)) {
347
            print fread($fm, min(1024 * 16, ($end - $cur) + 1));
348
            $cur += 1024 * 16;
349
        }
350
    }
351
    /**
352
     * This function streams a file to the client.
353
     *
354
     * @param string $full_file_name
355
     * @param bool   $forced
356
     * @param string $name
357
     * @param bool   $fixLinksHttpToHttps change file content from http to https
358
     *
359
     * @return false if file doesn't exist, true if stream succeeded
360
     */
361
    public static function file_send_for_download(
362
        $full_file_name,
363
        $forced = false,
364
        $name = '',
365
        $fixLinksHttpToHttps = false
366
    ) {
367
        session_write_close(); //we do not need write access to session anymore
368
        if (!is_file($full_file_name)) {
369
            return false;
370
        }
371
        $filename = $name == '' ? basename($full_file_name) : api_replace_dangerous_char($name);
372
        $len = filesize($full_file_name);
373
        // Fixing error when file name contains a ","
374
        $filename = str_replace(',', '', $filename);
375
        $sendFileHeaders = api_get_configuration_value('enable_x_sendfile_headers');
376
377
        // Allows chrome to make videos and audios seekable
378
        header('Accept-Ranges: bytes');
379
380
        if ($forced) {
381
            // Force the browser to save the file instead of opening it
382
            if (isset($sendFileHeaders) &&
383
                !empty($sendFileHeaders)) {
384
                header("X-Sendfile: $filename");
385
            }
386
387
            header('Content-type: application/octet-stream');
388
            header('Content-length: '.$len);
389
            if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
390
                header('Content-Disposition: filename= '.$filename);
391
            } else {
392
                header('Content-Disposition: attachment; filename= '.$filename);
393
            }
394
            if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
395
                header('Pragma: ');
396
                header('Cache-Control: ');
397
                header('Cache-Control: public'); // IE cannot download from sessions without a cache
398
            }
399
            header('Content-Description: '.$filename);
400
            header('Content-Transfer-Encoding: binary');
401
402
            if (function_exists('ob_end_clean') && ob_get_length()) {
403
                // Use ob_end_clean() to avoid weird buffering situations
404
                // where file is sent broken/incomplete for download
405
                ob_end_clean();
406
            }
407
408
            $res = fopen($full_file_name, 'r');
409
            fpassthru($res);
410
411
            return true;
412
        } else {
413
            // no forced download, just let the browser decide what to do according to the mimetype
414
            $lpFixedEncoding = api_get_setting('lp.fixed_encoding') === 'true';
415
416
            // Commented to let courses content to be cached in order to improve performance:
417
            //header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
418
            //header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
419
420
            // Commented to avoid double caching declaration when playing with IE and HTTPS
421
            //header('Cache-Control: no-cache, must-revalidate');
422
            //header('Pragma: no-cache');
423
424
            $contentType = self::file_get_mime_type($filename);
425
426
            switch ($contentType) {
427
                case 'text/html':
428
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
429
                        $contentType .= '; charset=UTF-8';
430
                    } else {
431
                        $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
432
                        if (!empty($encoding)) {
433
                            $contentType .= '; charset='.$encoding;
434
                        }
435
                    }
436
                    break;
437
                case 'text/plain':
438
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
439
                        $contentType .= '; charset=UTF-8';
440
                    } else {
441
                        $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
442
                        if (!empty($encoding)) {
443
                            $contentType .= '; charset='.$encoding;
444
                        }
445
                    }
446
                    break;
447
				case 'video/mp4':
448
				case 'audio/mpeg':
449
				case 'audio/mp4':
450
				case 'audio/ogg':
451
				case 'audio/webm':
452
				case 'audio/wav':
453
				case 'video/ogg':
454
				case 'video/webm':		
455
					self::smartReadFile($full_file_name,$filename,$contentType);
456
					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...
457
                case 'application/vnd.dwg':
458
                case 'application/vnd.dwf':
459
                    header('Content-type: application/octet-stream');
460
                    break;
461
            }
462
463
            header('Content-type: '.$contentType);
464
            header('Content-Length: '.$len);
465
            $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);
466
467
            if (strpos($userAgent, 'msie')) {
468
                header('Content-Disposition: ; filename= '.$filename);
469
            } else {
470
                //header('Content-Disposition: inline');
471
                header('Content-Disposition: inline;');
472
            }
473
474
            if ($fixLinksHttpToHttps) {
475
                $content = file_get_contents($full_file_name);
476
                $content = str_replace(
477
                    ['http%3A%2F%2F', 'http://'],
478
                    ['https%3A%2F%2F', 'https://'],
479
                    $content
480
                );
481
                echo $content;
482
            } else {
483
                if (function_exists('ob_end_clean') && ob_get_length()) {
484
                    // Use ob_end_clean() to avoid weird buffering situations
485
                    // where file is sent broken/incomplete for download
486
                    ob_end_clean();
487
                }
488
489
                readfile($full_file_name);
490
            }
491
492
            return true;
493
        }
494
    }
495
496
    /**
497
     * Session folder filters.
498
     *
499
     * @param string $path
500
     * @param int    $sessionId
501
     *
502
     * @return string|null
503
     */
504
    public static function getSessionFolderFilters($path, $sessionId)
505
    {
506
        $sessionId = (int) $sessionId;
507
        $condition = null;
508
509
        if (!empty($sessionId)) {
510
            // Chat folder filter
511
            if ($path == '/chat_files') {
512
                $condition .= " AND (docs.session_id = '$sessionId') ";
513
            }
514
            // share_folder filter
515
            $condition .= " AND docs.path != '/shared_folder' ";
516
        }
517
518
        return $condition;
519
    }
520
521
    /**
522
     * Fetches all document data for the given user/group.
523
     *
524
     * @param array     $courseInfo
525
     * @param string    $path
526
     * @param int       $toGroupId       iid
527
     * @param int       $toUserId
528
     * @param bool      $canSeeInvisible
529
     * @param bool      $search
530
     * @param int       $sessionId
531
     * @param User|null $currentUser
532
     *
533
     * @return array with all document data
534
     */
535
    public static function getAllDocumentData(
536
        $courseInfo,
537
        $path = '/',
538
        $toGroupId = 0,
539
        $toUserId = null,
540
        $canSeeInvisible = false,
541
        $search = false,
542
        $sessionId = 0,
543
        User $currentUser = null
544
    ) {
545
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
546
        $currentUser = $currentUser ?: api_get_current_user();
547
548
        $userGroupFilter = '';
549
        if (!is_null($toUserId)) {
550
            $toUserId = (int) $toUserId;
551
            $userGroupFilter = "last.to_user_id = $toUserId";
552
            if (empty($toUserId)) {
553
                $userGroupFilter = " (last.to_user_id = 0 OR last.to_user_id IS NULL) ";
554
            }
555
        } else {
556
            $toGroupId = (int) $toGroupId;
557
            $userGroupFilter = "last.to_group_id = $toGroupId";
558
            if (empty($toGroupId)) {
559
                $userGroupFilter = "( last.to_group_id = 0 OR last.to_group_id IS NULL) ";
560
            }
561
        }
562
563
        // Escape underscores in the path so they don't act as a wildcard
564
        $originalPath = $path;
565
        $path = str_replace('_', '\_', $path);
566
567
        $visibilityBit = ' <> 2';
568
569
        // The given path will not end with a slash, unless it's the root '/'
570
        // so no root -> add slash
571
        $addedSlash = $path == '/' ? '' : '/';
572
573
        // Condition for the session
574
        $sessionId = $sessionId ?: api_get_session_id();
575
        $conditionSession = " AND (last.session_id = '$sessionId' OR (last.session_id = '0' OR last.session_id IS NULL) )";
576
        $conditionSession .= self::getSessionFolderFilters($originalPath, $sessionId);
577
578
        $sharedCondition = null;
579
        if ($originalPath == '/shared_folder') {
580
            $students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
581
            if (!empty($students)) {
582
                $conditionList = [];
583
                foreach ($students as $studentInfo) {
584
                    $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
585
                }
586
                $sharedCondition .= ' AND docs.path IN ("'.implode('","', $conditionList).'")';
587
            }
588
        }
589
590
        $sql = "SELECT
591
                    docs.id,
592
                    docs.filetype,
593
                    docs.path,
594
                    docs.title,
595
                    docs.comment,
596
                    docs.size,
597
                    docs.readonly,
598
                    docs.session_id,
599
                    creator_id,
600
                    visibility,
601
                    n.updated_at,
602
                    n.created_at,
603
                    n.creator_id                                     
604
                FROM resource_node AS n
605
                INNER JOIN $tblDocument AS docs
606
                ON (docs.resource_node_id = n.id)
607
                INNER JOIN resource_link l
608
                ON (l.resource_node_id = n.id)                
609
                WHERE
610
                    docs.c_id = {$courseInfo['real_id']} AND                    
611
                    docs.path LIKE '".Database::escape_string($path.$addedSlash.'%')."' AND
612
                    docs.path NOT LIKE '".Database::escape_string($path.$addedSlash.'%/%')."' AND
613
                    docs.path NOT LIKE '%_DELETED_%' AND
614
                    l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')
615
                    $sharedCondition               
616
                ";
617
        //$userGroupFilter AND
618
        //$conditionSession
619
        $result = Database::query($sql);
620
621
        $documentData = [];
622
        $isAllowedToEdit = api_is_allowed_to_edit(null, true);
623
        $isCoach = api_is_coach();
624
        if ($result !== false && Database::num_rows($result) != 0) {
625
            $rows = [];
626
627
            $hideInvisibleDocuments = api_get_configuration_value('hide_invisible_course_documents_in_sessions');
628
629
            while ($row = Database::fetch_array($result, 'ASSOC')) {
630
                if (isset($rows[$row['id']])) {
631
                    continue;
632
                }
633
634
                // If we are in session and hide_invisible_course_documents_in_sessions is enabled
635
                // Then we avoid the documents that have visibility in session but that they come from a base course
636
                if ($hideInvisibleDocuments && $sessionId) {
637
                    if ($row['item_property_session_id'] == $sessionId && empty($row['session_id'])) {
638
                        continue;
639
                    }
640
                }
641
642
                $rows[$row['id']] = $row;
643
            }
644
645
            // If we are in session and hide_invisible_course_documents_in_sessions is enabled
646
            // Or if we are students
647
            // Then don't list the invisible or deleted documents
648
            if (($sessionId && $hideInvisibleDocuments) || (!$isCoach && !$isAllowedToEdit)) {
649
                $rows = array_filter($rows, function ($row) {
650
                    if (in_array(
651
                        $row['visibility'],
652
                        [
653
                            ResourceLink::VISIBILITY_DELETED,
654
                            ResourceLink::VISIBILITY_DRAFT,
655
                        ]
656
                    )) {
657
                        return false;
658
                    }
659
660
                    return true;
661
                });
662
            }
663
664
            foreach ($rows as $row) {
665
                if ($row['filetype'] == 'file' &&
666
                    pathinfo($row['path'], PATHINFO_EXTENSION) == 'html'
667
                ) {
668
                    // Templates management
669
                    $tblTemplate = Database::get_main_table(TABLE_MAIN_TEMPLATES);
670
                    $sql = "SELECT id FROM $tblTemplate
671
                            WHERE
672
                                c_id = '".$courseInfo['real_id']."' AND
673
                                user_id = '".$currentUser->getId()."' AND
674
                                ref_doc = '".$row['id']."'";
675
                    $templateResult = Database::query($sql);
676
                    $row['is_template'] = (Database::num_rows($templateResult) > 0) ? 1 : 0;
677
                }
678
                $row['basename'] = basename($row['path']);
679
                // Just filling $document_data.
680
                $documentData[$row['id']] = $row;
681
            }
682
683
            // Only for the student we filter the results see BT#1652
684
            if (!$isCoach && !$isAllowedToEdit) {
685
                // Checking parents visibility.
686
                $finalDocumentData = [];
687
                foreach ($documentData as $row) {
688
                    $isVisible = self::check_visibility_tree(
689
                        $row['id'],
690
                        $courseInfo,
691
                        $sessionId,
692
                        $currentUser->getId(),
693
                        $toGroupId
694
                    );
695
                    if ($isVisible) {
696
                        $finalDocumentData[$row['id']] = $row;
697
                    }
698
                }
699
            } else {
700
                $finalDocumentData = $documentData;
701
            }
702
703
            return $finalDocumentData;
704
        } else {
705
            return [];
706
        }
707
    }
708
709
    /**
710
     * Gets the paths of all folders in a course
711
     * can show all folders (except for the deleted ones) or only visible ones.
712
     *
713
     * @param array  $courseInfo
714
     * @param int    $groupIid          iid
715
     * @param bool   $can_see_invisible
716
     * @param bool   $getInvisibleList
717
     * @param string $path              current path
718
     *
719
     * @return array with paths
720
     */
721
    public static function get_all_document_folders(
722
        $courseInfo,
723
        $groupIid = 0,
724
        $can_see_invisible = false,
725
        $getInvisibleList = false,
726
        $path = ''
727
    ) {
728
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
729
        $groupIid = (int) $groupIid;
730
        $courseId = $courseInfo['real_id'];
731
        $sessionId = api_get_session_id();
732
733
        $folders = [];
734
        $students = CourseManager::get_user_list_from_course_code(
735
            $courseInfo['code'],
736
            api_get_session_id()
737
        );
738
739
        $conditionList = [];
740
        if (!empty($students)) {
741
            foreach ($students as $studentId => $studentInfo) {
742
                $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
743
            }
744
        }
745
746
        $groupCondition = " l.group_id = $groupIid";
747
        if (empty($groupIid)) {
748
            $groupCondition = ' (l.group_id = 0 OR l.group_id IS NULL)';
749
        }
750
751
        $show_users_condition = '';
752
        if (api_get_setting('show_users_folders') === 'false') {
753
            $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
754
        }
755
756
        if ($can_see_invisible) {
757
            $sessionId = $sessionId ?: api_get_session_id();
758
            $condition_session = " AND (l.session_id = '$sessionId' OR (l.session_id = '0' OR l.session_id IS NULL) )";
759
            $condition_session .= self::getSessionFolderFilters($path, $sessionId);
760
761
            $sql = "SELECT DISTINCT docs.id, docs.path
762
                    FROM resource_node AS n
763
                    INNER JOIN $TABLE_DOCUMENT  AS docs
764
                    ON (docs.resource_node_id = n.id)
765
                    INNER JOIN resource_link l
766
                    ON (l.resource_node_id = n.id)
767
                    WHERE                      
768
                        docs.c_id = $courseId AND
769
                        docs.filetype = 'folder' AND
770
                        $groupCondition AND
771
                        docs.path NOT LIKE '%shared_folder%' AND
772
                        docs.path NOT LIKE '%_DELETED_%' AND
773
                        l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')                           
774
                        $condition_session ";
775
776
            if ($groupIid != 0) {
777
                $sql .= " AND docs.path NOT LIKE '%shared_folder%' ";
778
            } else {
779
                $sql .= $show_users_condition;
780
            }
781
782
            $result = Database::query($sql);
783
            if ($result && Database::num_rows($result) != 0) {
784
                while ($row = Database::fetch_array($result, 'ASSOC')) {
785
                    if (self::is_folder_to_avoid($row['path'])) {
786
                        continue;
787
                    }
788
789
                    if (strpos($row['path'], '/shared_folder/') !== false) {
790
                        if (!in_array($row['path'], $conditionList)) {
791
                            continue;
792
                        }
793
                    }
794
795
                    $folders[$row['id']] = $row['path'];
796
                }
797
798
                if (!empty($folders)) {
799
                    natsort($folders);
800
                }
801
802
                return $folders;
803
            } else {
804
                return false;
805
            }
806
        } else {
807
            // No invisible folders
808
            // Condition for the session
809
            $condition_session = api_get_session_condition(
810
                $sessionId,
811
                true,
812
                false,
813
                'docs.session_id'
814
            );
815
816
            $visibilityCondition = 'l.visibility = 1';
817
            $fileType = "docs.filetype = 'folder' AND";
818
            if ($getInvisibleList) {
819
                $visibilityCondition = 'l.visibility = 0';
820
                $fileType = '';
821
            }
822
823
            //get visible folders
824
            $sql = "SELECT DISTINCT docs.id, docs.path
825
                    FROM resource_node AS n
826
                    INNER JOIN $TABLE_DOCUMENT  AS docs
827
                    ON (docs.resource_node_id = n.id)
828
                    INNER JOIN resource_link l
829
                    ON (l.resource_node_id = n.id)
830
                    WHERE
831
                        $fileType                        
832
                        $groupCondition AND
833
                        $visibilityCondition
834
                        $show_users_condition
835
                        $condition_session AND                        
836
                        docs.c_id = $courseId ";
837
            $result = Database::query($sql);
838
            $visibleFolders = [];
839
            while ($row = Database::fetch_array($result, 'ASSOC')) {
840
                $visibleFolders[$row['id']] = $row['path'];
841
            }
842
843
            if ($getInvisibleList) {
844
                return $visibleFolders;
845
            }
846
847
            // get invisible folders
848
            $sql = "SELECT DISTINCT docs.id, docs.path
849
                    FROM resource_node AS n
850
                    INNER JOIN $TABLE_DOCUMENT  AS docs
851
                    ON (docs.resource_node_id = n.id)
852
                    INNER JOIN resource_link l
853
                    ON (l.resource_node_id = n.id)
854
                    WHERE                        
855
                        docs.filetype = 'folder' AND                        
856
                        $groupCondition AND                        
857
                        l.visibility IN ('".ResourceLink::VISIBILITY_PENDING."') 
858
                        $condition_session AND                        
859
                        docs.c_id = $courseId ";
860
            $result = Database::query($sql);
861
            $invisibleFolders = [];
862
            while ($row = Database::fetch_array($result, 'ASSOC')) {
863
                //get visible folders in the invisible ones -> they are invisible too
864
                $sql = "SELECT DISTINCT docs.id, docs.path
865
                        FROM resource_node AS n
866
                        INNER JOIN $TABLE_DOCUMENT  AS docs
867
                        ON (docs.resource_node_id = n.id)
868
                        INNER JOIN resource_link l
869
                        ON (l.resource_node_id = n.id)
870
                        WHERE                            
871
                            docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
872
                            docs.filetype = 'folder' AND                            
873
                            $groupCondition AND
874
                            l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."') 
875
                            $condition_session AND                            
876
                            docs.c_id = $courseId ";
877
                $folder_in_invisible_result = Database::query($sql);
878
                while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
879
                    $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
880
                }
881
            }
882
883
            // If both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
884
            if (is_array($visibleFolders) && is_array($invisibleFolders)) {
885
                $folders = array_diff($visibleFolders, $invisibleFolders);
886
                natsort($folders);
887
888
                return $folders;
889
            }
890
891
            if (is_array($visibleFolders)) {
892
                natsort($visibleFolders);
893
894
                return $visibleFolders;
895
            }
896
897
            // no visible folders found
898
            return false;
899
        }
900
    }
901
902
    /**
903
     * This check if a document has the readonly property checked, then see if the user
904
     * is the owner of this file, if all this is true then return true.
905
     *
906
     * @param array  $_course
907
     * @param int    $user_id     id of the current user
908
     * @param string $file        path stored in the database (if not defined, $documentId must be used)
909
     * @param int    $document_id in case you don't have the file path ,
910
     *                            insert the id of the file here and leave $file in blank ''
911
     * @param bool   $to_delete
912
     * @param int    $sessionId
913
     *
914
     * @return bool true/false
915
     * */
916
    public static function check_readonly(
917
        $_course,
918
        $user_id,
919
        $file = null,
920
        $document_id = 0,
921
        $to_delete = false,
922
        $sessionId = null,
923
        $documentId = null
924
    ) {
925
        $sessionId = (int) $sessionId;
926
        if (empty($sessionId)) {
927
            $sessionId = api_get_session_id();
928
        }
929
        $document_id = (int) $document_id;
930
        if (empty($document_id)) {
931
            $document_id = self::get_document_id($_course, $file, $sessionId);
932
        }
933
934
        $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
935
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
936
        $course_id = $_course['real_id'];
937
938
        if ($to_delete) {
939
            if (self::isFolder($_course, $document_id)) {
940
                if (!empty($file)) {
941
                    $path = Database::escape_string($file);
942
                    // Check
943
                    $sql = "SELECT td.id, readonly, tp.insert_user_id
944
                            FROM $TABLE_DOCUMENT td 
945
                            INNER JOIN $TABLE_PROPERTY tp
946
                            ON (td.c_id = tp.c_id AND tp.ref= td.id)
947
                            WHERE
948
                                td.c_id = $course_id AND
949
                                tp.c_id = $course_id AND
950
                                td.session_id = $sessionId AND                                
951
                                (path='".$path."' OR path LIKE BINARY '".$path."/%' ) ";
952
                    // Get all id's of documents that are deleted
953
                    $what_to_check_result = Database::query($sql);
954
955
                    if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
956
                        // file with readonly set to 1 exist?
957
                        $readonly_set = false;
958
                        while ($row = Database::fetch_array($what_to_check_result)) {
959
                            //query to delete from item_property table
960
                            if ($row['readonly'] == 1) {
961
                                if (!($row['insert_user_id'] == $user_id)) {
962
                                    $readonly_set = true;
963
                                    break;
964
                                }
965
                            }
966
                        }
967
968
                        if ($readonly_set) {
969
                            return true;
970
                        }
971
                    }
972
                }
973
974
                return false;
975
            }
976
        }
977
978
        if (!empty($document_id)) {
979
            $sql = "SELECT a.insert_user_id, b.readonly
980
                   FROM $TABLE_PROPERTY a 
981
                   INNER JOIN $TABLE_DOCUMENT b
982
                   ON (a.c_id = b.c_id AND a.ref= b.id)
983
                   WHERE
984
            			a.c_id = $course_id AND
985
                        b.c_id = $course_id AND
986
            			a.ref = $document_id 
987
                    LIMIT 1";
988
            $result = Database::query($sql);
989
            $doc_details = Database::fetch_array($result, 'ASSOC');
990
991
            if ($doc_details['readonly'] == 1) {
992
                return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
993
            }
994
        }
995
996
        return false;
997
    }
998
999
    /**
1000
     * This check if a document is a folder or not.
1001
     *
1002
     * @param array $_course
1003
     * @param int   $id      document id
1004
     *
1005
     * @return bool true/false
1006
     * */
1007
    public static function isFolder($_course, $id)
1008
    {
1009
        $table = Database::get_course_table(TABLE_DOCUMENT);
1010
        if (empty($_course)) {
1011
            return false;
1012
        }
1013
        $course_id = $_course['real_id'];
1014
        $id = (int) $id;
1015
        $sql = "SELECT filetype FROM $table
1016
                WHERE c_id = $course_id AND id= $id";
1017
        $result = Database::fetch_array(Database::query($sql), 'ASSOC');
1018
1019
        return $result['filetype'] === 'folder';
1020
    }
1021
1022
    /**
1023
     * @param int   $document_id
1024
     * @param array $course_info
1025
     * @param int   $session_id
1026
     * @param bool  $remove_content_from_db
1027
     */
1028
    public static function deleteDocumentFromDb(
1029
        $document_id,
1030
        $course_info = [],
1031
        $session_id = 0,
1032
        $remove_content_from_db = false
1033
    ) {
1034
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1035
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
1036
1037
        // Deleting from the DB
1038
        $user_id = api_get_user_id();
1039
        $document_id = intval($document_id);
1040
1041
        if (empty($course_info)) {
1042
            $course_info = api_get_course_info();
1043
        }
1044
1045
        if (empty($session_id)) {
1046
            $session_id = api_get_session_id();
1047
        }
1048
        // Soft DB delete
1049
        api_item_property_update(
1050
            $course_info,
1051
            TOOL_DOCUMENT,
1052
            $document_id,
1053
            'delete',
1054
            $user_id,
1055
            null,
1056
            null,
1057
            null,
1058
            null,
1059
            $session_id
1060
        );
1061
        self::delete_document_from_search_engine($course_info['code'], $document_id);
1062
        self::unsetDocumentAsTemplate($document_id, $course_info['real_id'], $user_id);
1063
1064
        //Hard DB delete
1065
        if ($remove_content_from_db) {
1066
            $sql = "DELETE FROM $TABLE_ITEMPROPERTY
1067
                    WHERE
1068
                        c_id = {$course_info['real_id']} AND
1069
                        ref = ".$document_id." AND
1070
                        tool='".TOOL_DOCUMENT."'";
1071
            Database::query($sql);
1072
1073
            $sql = "DELETE FROM $TABLE_DOCUMENT
1074
                    WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
1075
            Database::query($sql);
1076
        }
1077
    }
1078
1079
    /**
1080
     * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
1081
     * Files/folders that are inside a deleted folder get visibility 2.
1082
     *
1083
     * @param array  $_course
1084
     * @param string $path          Path stored in the database
1085
     * @param string $base_work_dir Path to the documents folder (if not defined, $documentId must be used)
1086
     * @param int    $sessionId     The ID of the session, if any
1087
     * @param int    $documentId    The document id, if available
1088
     * @param int    $groupId       iid
1089
     *
1090
     * @return bool true/false
1091
     *
1092
     * @todo now only files/folders in a folder get visibility 2, we should rename them too.
1093
     * @todo We should be able to get rid of this later when using only documentId (check further usage)
1094
     */
1095
    public static function delete_document(
1096
        $_course,
1097
        $path = null,
1098
        $base_work_dir = null,
1099
        $sessionId = null,
1100
        $documentId = null,
1101
        $groupId = 0
1102
    ) {
1103
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1104
1105
        $groupId = (int) $groupId;
1106
        if (empty($groupId)) {
1107
            $groupId = api_get_group_id();
1108
        }
1109
1110
        $sessionId = (int) $sessionId;
1111
        if (empty($sessionId)) {
1112
            $sessionId = api_get_session_id();
1113
        }
1114
1115
        $course_id = $_course['real_id'];
1116
1117
        if (empty($course_id)) {
1118
            return false;
1119
        }
1120
1121
        if (empty($base_work_dir)) {
1122
            return false;
1123
        }
1124
1125
        if (empty($documentId)) {
1126
            $documentId = self::get_document_id($_course, $path, $sessionId);
1127
            $docInfo = self::get_document_data_by_id(
1128
                $documentId,
1129
                $_course['code'],
1130
                false,
1131
                $sessionId
1132
            );
1133
            $path = $docInfo['path'];
1134
        } else {
1135
            $docInfo = self::get_document_data_by_id(
1136
                $documentId,
1137
                $_course['code'],
1138
                false,
1139
                $sessionId
1140
            );
1141
            if (empty($docInfo)) {
1142
                return false;
1143
            }
1144
            $path = $docInfo['path'];
1145
        }
1146
1147
        $em = Database::getManager();
1148
        $documentId = (int) $documentId;
1149
1150
        if (empty($path) || empty($docInfo) || empty($documentId)) {
1151
            return false;
1152
        }
1153
1154
        /** @var CDocument $document */
1155
        $document = $em->getRepository('ChamiloCourseBundle:CDocument')->find($docInfo['iid']);
1156
        $document->setSoftDelete();
1157
        $em->persist($document);
1158
        $em->flush();
1159
1160
        return true;
1161
1162
        $itemInfo = api_get_item_property_info(
0 ignored issues
show
Unused Code introduced by
$itemInfo = api_get_item..., $sessionId, $groupId) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1163
            $_course['real_id'],
1164
            TOOL_DOCUMENT,
1165
            $documentId,
1166
            $sessionId,
1167
            $groupId
1168
        );
1169
1170
        if (empty($itemInfo)) {
1171
            return false;
1172
        }
1173
1174
        // File was already deleted.
1175
        if ($itemInfo['lastedit_type'] == 'DocumentDeleted' ||
1176
            $itemInfo['lastedit_type'] == 'delete' ||
1177
            $itemInfo['visibility'] == 2
1178
        ) {
1179
            return false;
1180
        }
1181
1182
        // Filtering by group.
1183
        if ($itemInfo['to_group_id'] != $groupId) {
1184
            return false;
1185
        }
1186
1187
        $document_exists_in_disk = file_exists($base_work_dir.$path);
1188
        $new_path = $path.'_DELETED_'.$documentId;
1189
1190
        $file_deleted_from_db = false;
1191
        $file_deleted_from_disk = false;
1192
        $file_renamed_from_disk = false;
1193
1194
        if ($documentId) {
1195
            // Deleting doc from the DB.
1196
            self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1197
            // Checking
1198
            // $file_exists_in_db = self::get_document_data_by_id($documentId, $_course['code']);
1199
            $file_deleted_from_db = true;
1200
        }
1201
1202
        // Looking for children.
1203
        if ($docInfo['filetype'] == 'folder') {
1204
            $cleanPath = Database::escape_string($path);
1205
1206
            // Deleted files inside this folder.
1207
            $sql = "SELECT id FROM $TABLE_DOCUMENT
1208
                    WHERE
1209
                        c_id = $course_id AND
1210
                        session_id = $sessionId AND
1211
                        path LIKE BINARY '".$cleanPath."/%'";
1212
1213
            // Get all id's of documents that are deleted.
1214
            $result = Database::query($sql);
1215
1216
            if ($result && Database::num_rows($result) != 0) {
1217
                // Recursive delete.
1218
                while ($row = Database::fetch_array($result)) {
1219
                    self::delete_document(
1220
                        $_course,
1221
                        null,
1222
                        $base_work_dir,
1223
                        $sessionId,
1224
                        $row['id'],
1225
                        $groupId
1226
                    );
1227
                }
1228
            }
1229
        }
1230
1231
        if ($document_exists_in_disk) {
1232
            if (api_get_setting('permanently_remove_deleted_files') === 'true') {
1233
                // Delete documents, do it like this so metadata gets deleted too
1234
                my_delete($base_work_dir.$path);
1235
                // Hard delete.
1236
                self::deleteDocumentFromDb($documentId, $_course, $sessionId, true);
1237
                $file_deleted_from_disk = true;
1238
            } else {
1239
                // Set visibility to 2 and rename file/folder to xxx_DELETED_#id (soft delete)
1240
                if (is_file($base_work_dir.$path) || is_dir($base_work_dir.$path)) {
1241
                    if (rename($base_work_dir.$path, $base_work_dir.$new_path)) {
1242
                        $new_path = Database::escape_string($new_path);
1243
1244
                        $sql = "UPDATE $TABLE_DOCUMENT
1245
                                SET path = '".$new_path."'
1246
                                WHERE
1247
                                    c_id = $course_id AND
1248
                                    session_id = $sessionId AND
1249
                                    id = ".$documentId;
1250
                        Database::query($sql);
1251
1252
                        // Soft delete.
1253
                        self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1254
1255
                        // Change path of sub folders and documents in database.
1256
                        $old_item_path = $docInfo['path'];
1257
                        $new_item_path = $new_path.substr($old_item_path, strlen($path));
1258
                        $new_item_path = Database::escape_string($new_item_path);
1259
1260
                        $sql = "UPDATE $TABLE_DOCUMENT
1261
                                SET path = '".$new_item_path."'
1262
                                WHERE
1263
                                    c_id = $course_id AND
1264
                                    session_id = $sessionId AND
1265
                                    id = ".$documentId;
1266
                        Database::query($sql);
1267
1268
                        $file_renamed_from_disk = true;
1269
                    } else {
1270
                        // Couldn't rename - file permissions problem?
1271
                        error_log(
1272
                            __FILE__.' '.__LINE__.': Error renaming '.$base_work_dir.$path.' to '.$base_work_dir.$new_path.'. This is probably due to file permissions',
1273
                            0
1274
                        );
1275
                    }
1276
                }
1277
            }
1278
        }
1279
        // Checking inconsistency
1280
        //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').')');
1281
        if ($file_deleted_from_db && $file_deleted_from_disk ||
1282
            $file_deleted_from_db && $file_renamed_from_disk
1283
        ) {
1284
            return true;
1285
        } else {
1286
            //Something went wrong
1287
            //The file or directory isn't there anymore (on the filesystem)
1288
            // This means it has been removed externally. To prevent a
1289
            // blocking error from happening, we drop the related items from the
1290
            // item_property and the document table.
1291
            error_log(
1292
                __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',
1293
                0
1294
            );
1295
1296
            return false;
1297
        }
1298
    }
1299
1300
    /**
1301
     * Removes documents from search engine database.
1302
     *
1303
     * @param string $course_id   Course code
1304
     * @param int    $document_id Document id to delete
1305
     */
1306
    public static function delete_document_from_search_engine($course_id, $document_id)
1307
    {
1308
        // remove from search engine if enabled
1309
        if (api_get_setting('search_enabled') === 'true') {
1310
            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
1311
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1312
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1313
            $res = Database::query($sql);
1314
            if (Database::num_rows($res) > 0) {
1315
                $row2 = Database::fetch_array($res);
1316
                $di = new ChamiloIndexer();
1317
                $di->remove_document($row2['search_did']);
1318
            }
1319
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1320
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1321
            Database::query($sql);
1322
1323
            // remove terms from db
1324
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1325
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $document_id);
1326
        }
1327
    }
1328
1329
    /**
1330
     * Gets the id of a document with a given path.
1331
     *
1332
     * @param array  $courseInfo
1333
     * @param string $path
1334
     * @param int    $sessionId
1335
     *
1336
     * @return int id of document / false if no doc found
1337
     */
1338
    public static function get_document_id($courseInfo, $path, $sessionId = 0)
1339
    {
1340
        $table = Database::get_course_table(TABLE_DOCUMENT);
1341
        $courseId = $courseInfo['real_id'];
1342
1343
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
1344
        $sessionCondition = api_get_session_condition($sessionId, true);
1345
1346
        $path = Database::escape_string($path);
1347
        if (!empty($courseId) && !empty($path)) {
1348
            $sql = "SELECT id FROM $table
1349
                    WHERE
1350
                        c_id = $courseId AND
1351
                        path LIKE BINARY '$path'
1352
                        $sessionCondition
1353
                    LIMIT 1";
1354
1355
            $result = Database::query($sql);
1356
            if (Database::num_rows($result)) {
1357
                $row = Database::fetch_array($result);
1358
1359
                return (int) $row['id'];
1360
            }
1361
        }
1362
1363
        return false;
1364
    }
1365
1366
    /**
1367
     * Gets the document data with a given id.
1368
     *
1369
     * @param int    $id            Document Id (id field in c_document table)
1370
     * @param string $course_code   Course code
1371
     * @param bool   $load_parents  load folder parents
1372
     * @param int    $session_id    The session ID,
1373
     *                              0 if requires context *out of* session, and null to use global context
1374
     * @param bool   $ignoreDeleted
1375
     *
1376
     * @return array document content
1377
     */
1378
    public static function get_document_data_by_id(
1379
        $id,
1380
        $course_code,
1381
        $load_parents = false,
1382
        $session_id = null,
1383
        $ignoreDeleted = false
1384
    ) {
1385
        $course_info = api_get_course_info($course_code);
1386
        $course_id = $course_info['real_id'];
1387
1388
        if (empty($course_info)) {
1389
            return false;
1390
        }
1391
1392
        $session_id = empty($session_id) ? api_get_session_id() : (int) $session_id;
1393
        $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
1394
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1395
        $id = (int) $id;
1396
        $sessionCondition = api_get_session_condition($session_id, true, true);
1397
1398
        $sql = "SELECT * FROM $TABLE_DOCUMENT
1399
                WHERE c_id = $course_id $sessionCondition AND id = $id";
1400
1401
        if ($ignoreDeleted) {
1402
            $sql .= " AND path NOT LIKE '%_DELETED_%' ";
1403
        }
1404
1405
        $result = Database::query($sql);
1406
        if ($result && Database::num_rows($result) == 1) {
1407
            $row = Database::fetch_array($result, 'ASSOC');
1408
            //@todo need to clarify the name of the URLs not nice right now
1409
            $url_path = urlencode($row['path']);
1410
            $path = str_replace('%2F', '/', $url_path);
1411
            $pathinfo = pathinfo($row['path']);
1412
            $row['url'] = api_get_path(WEB_CODE_PATH).'document/showinframes.php?cidReq='.$course_code.'&id='.$id;
1413
            $row['document_url'] = api_get_path(WEB_CODE_PATH).'document/document.php?cidReq='.$course_code.'&id='.$id;
1414
            $row['absolute_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
1415
            $row['absolute_path_from_document'] = '/document'.$row['path'];
1416
            $row['absolute_parent_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$pathinfo['dirname'].'/';
1417
            $row['direct_url'] = $www.$path;
1418
            $row['basename'] = basename($row['path']);
1419
1420
            if (dirname($row['path']) == '.') {
1421
                $row['parent_id'] = '0';
1422
            } else {
1423
                $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), $session_id);
1424
                if (empty($row['parent_id'])) {
1425
                    // Try one more with session id = 0
1426
                    $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), 0);
1427
                }
1428
            }
1429
            $parents = [];
1430
1431
            //Use to generate parents (needed for the breadcrumb)
1432
            //@todo sorry but this for is here because there's not a parent_id in the document table so we parsed the path!!
1433
            if ($load_parents) {
1434
                $dir_array = explode('/', $row['path']);
1435
                $dir_array = array_filter($dir_array);
1436
                $array_len = count($dir_array) + 1;
1437
                $real_dir = '';
1438
1439
                for ($i = 1; $i < $array_len; $i++) {
1440
                    $real_dir .= '/'.(isset($dir_array[$i]) ? $dir_array[$i] : '');
1441
                    $parent_id = self::get_document_id($course_info, $real_dir);
1442
                    if ($session_id != 0 && empty($parent_id)) {
1443
                        $parent_id = self::get_document_id($course_info, $real_dir, 0);
1444
                    }
1445
                    if (!empty($parent_id)) {
1446
                        $sub_document_data = self::get_document_data_by_id(
1447
                            $parent_id,
1448
                            $course_code,
1449
                            false,
1450
                            $session_id
1451
                        );
1452
                        if ($session_id != 0 and !$sub_document_data) {
1453
                            $sub_document_data = self::get_document_data_by_id(
1454
                                $parent_id,
1455
                                $course_code,
1456
                                false,
1457
                                0
1458
                            );
1459
                        }
1460
                        //@todo add visibility here
1461
                        $parents[] = $sub_document_data;
1462
                    }
1463
                }
1464
            }
1465
            $row['parents'] = $parents;
1466
1467
            return $row;
1468
        }
1469
1470
        return false;
1471
    }
1472
1473
    /**
1474
     * Allow to set a specific document as a new template for CKeditor
1475
     * for a particular user in a particular course.
1476
     *
1477
     * @param string $title
1478
     * @param string $description
1479
     * @param int    $document_id_for_template the document id
1480
     * @param int    $courseId
1481
     * @param int    $user_id
1482
     * @param string $image
1483
     *
1484
     * @return bool
1485
     */
1486
    public static function setDocumentAsTemplate(
1487
        $title,
1488
        $description,
1489
        $document_id_for_template,
1490
        $courseId,
1491
        $user_id,
1492
        $image
1493
    ) {
1494
        // Database table definition
1495
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1496
        $params = [
1497
            'title' => $title,
1498
            'description' => $description,
1499
            'c_id' => $courseId,
1500
            'user_id' => $user_id,
1501
            'ref_doc' => $document_id_for_template,
1502
            'image' => $image,
1503
        ];
1504
        Database::insert($table_template, $params);
1505
1506
        return true;
1507
    }
1508
1509
    /**
1510
     * Unset a document as template.
1511
     *
1512
     * @param int $document_id
1513
     * @param int $courseId
1514
     * @param int $user_id
1515
     */
1516
    public static function unsetDocumentAsTemplate(
1517
        $document_id,
1518
        $courseId,
1519
        $user_id
1520
    ) {
1521
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1522
        $courseId = (int) $courseId;
1523
        $user_id = (int) $user_id;
1524
        $document_id = (int) $document_id;
1525
1526
        $sql = 'SELECT id FROM '.$table_template.'
1527
                WHERE
1528
                    c_id = "'.$courseId.'" AND
1529
                    user_id = "'.$user_id.'" AND
1530
                    ref_doc = "'.$document_id.'"';
1531
        $result = Database::query($sql);
1532
        $template_id = Database::result($result, 0, 0);
1533
1534
        my_delete(api_get_path(SYS_CODE_PATH).'upload/template_thumbnails/'.$template_id.'.jpg');
1535
1536
        $sql = 'DELETE FROM '.$table_template.'
1537
                WHERE
1538
                    c_id ="'.$courseId.'" AND
1539
                    user_id="'.$user_id.'" AND
1540
                    ref_doc="'.$document_id.'"';
1541
1542
        Database::query($sql);
1543
    }
1544
1545
    /**
1546
     * Return true if the documentpath have visibility=1 as
1547
     * item_property (you should use the is_visible_by_id).
1548
     *
1549
     * @param string $doc_path the relative complete path of the document
1550
     * @param array  $course   the _course array info of the document's course
1551
     * @param int
1552
     * @param string
1553
     *
1554
     * @return bool
1555
     */
1556
    public static function is_visible(
1557
        $doc_path,
1558
        $course,
1559
        $session_id = 0,
1560
        $file_type = 'file'
1561
    ) {
1562
        $docTable = Database::get_course_table(TABLE_DOCUMENT);
1563
        $propTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
1564
1565
        $course_id = $course['real_id'];
1566
        // note the extra / at the end of doc_path to match every path in
1567
        // the document table that is part of the document path
1568
1569
        $session_id = intval($session_id);
1570
        $condition = "AND d.session_id IN  ('$session_id', '0') ";
1571
        // The " d.filetype='file' " let the user see a file even if the folder is hidden see #2198
1572
1573
        /*
1574
          When using hotpotatoes files, a new html files are generated
1575
          in the hotpotatoes folder to display the test.
1576
          The genuine html file is copied to math4.htm(user_id).t.html
1577
          Images files are not copied, and keep same name.
1578
          To check the html file visibility, we don't have to check file math4.htm(user_id).t.html but file math4.htm
1579
          In this case, we have to remove (user_id).t.html to check the visibility of the file
1580
          For images, we just check the path of the image file.
1581
1582
          Exemple of hotpotatoes folder :
1583
          A.jpg
1584
          maths4-consigne.jpg
1585
          maths4.htm
1586
          maths4.htm1.t.html
1587
          maths4.htm52.t.html
1588
          maths4.htm654.t.html
1589
          omega.jpg
1590
          theta.jpg
1591
         */
1592
1593
        if (strpos($doc_path, 'HotPotatoes_files') && preg_match("/\.t\.html$/", $doc_path)) {
1594
            $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
1595
        }
1596
1597
        if (!in_array($file_type, ['file', 'folder'])) {
1598
            $file_type = 'file';
1599
        }
1600
        $doc_path = Database::escape_string($doc_path).'/';
1601
1602
        $sql = "SELECT visibility
1603
                FROM $docTable d
1604
                INNER JOIN $propTable ip
1605
                ON (d.id = ip.ref AND d.c_id = ip.c_id)
1606
        		WHERE
1607
        		    d.c_id  = $course_id AND 
1608
        		    ip.c_id = $course_id AND
1609
        		    ip.tool = '".TOOL_DOCUMENT."' $condition AND
1610
        			filetype = '$file_type' AND
1611
        			locate(concat(path,'/'), '$doc_path')=1
1612
                ";
1613
1614
        $result = Database::query($sql);
1615
        $is_visible = false;
1616
        if (Database::num_rows($result) > 0) {
1617
            $row = Database::fetch_array($result, 'ASSOC');
1618
            if ($row['visibility'] == 1) {
1619
                $is_visible = api_is_allowed_in_course() || api_is_platform_admin();
1620
            }
1621
        }
1622
1623
        /* improved protection of documents viewable directly through the url:
1624
            incorporates the same protections of the course at the url of
1625
            documents:
1626
            access allowed for the whole world Open, access allowed for
1627
            users registered on the platform Private access, document accessible
1628
            only to course members (see the Users list), Completely closed;
1629
            the document is only accessible to the course admin and
1630
            teaching assistants.*/
1631
        //return $_SESSION ['is_allowed_in_course'] || api_is_platform_admin();
1632
        return $is_visible;
1633
    }
1634
1635
    /**
1636
     * Return true if user can see a file.
1637
     *
1638
     * @param   int     document id
1639
     * @param   array   course info
1640
     * @param   int
1641
     * @param   int
1642
     * @param bool
1643
     *
1644
     * @return bool
1645
     */
1646
    public static function is_visible_by_id(
1647
        $doc_id,
1648
        $course_info,
1649
        $session_id,
1650
        $user_id,
1651
        $admins_can_see_everything = true,
1652
        $userIsSubscribed = null
1653
    ) {
1654
        $user_in_course = false;
1655
1656
        //1. Checking the course array
1657
        if (empty($course_info)) {
1658
            $course_info = api_get_course_info();
1659
            if (empty($course_info)) {
1660
                return false;
1661
            }
1662
        }
1663
1664
        $doc_id = (int) $doc_id;
1665
        $session_id = (int) $session_id;
1666
        // 2. Course and Session visibility are handle in local.inc.php/global.inc.php
1667
        // 3. Checking if user exist in course/session
1668
        if ($session_id == 0) {
1669
            if (is_null($userIsSubscribed)) {
1670
                $userIsSubscribed = CourseManager::is_user_subscribed_in_course(
1671
                    $user_id,
1672
                    $course_info['code']
1673
                );
1674
            }
1675
1676
            if ($userIsSubscribed === true || api_is_platform_admin()) {
1677
                $user_in_course = true;
1678
            }
1679
1680
            // Check if course is open then we can consider that the student is registered to the course
1681
            if (isset($course_info) &&
1682
                in_array(
1683
                    $course_info['visibility'],
1684
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
1685
                )
1686
            ) {
1687
                $user_in_course = true;
1688
            }
1689
        } else {
1690
            $user_status = SessionManager::get_user_status_in_course_session(
1691
                $user_id,
1692
                $course_info['real_id'],
1693
                $session_id
1694
            );
1695
1696
            if (in_array($user_status, ['0', '2', '6'])) {
1697
                //is true if is an student, course session teacher or coach
1698
                $user_in_course = true;
1699
            }
1700
1701
            if (api_is_platform_admin()) {
1702
                $user_in_course = true;
1703
            }
1704
        }
1705
1706
        $em = Database::getManager();
1707
1708
        // 4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
1709
        if ($user_in_course) {
1710
            $repo = $em->getRepository('ChamiloCourseBundle:CDocument');
1711
            /** @var \Chamilo\CourseBundle\Entity\CDocument $document */
1712
            $document = $repo->find($doc_id);
1713
            $link = $document->getCourseSessionResourceLink();
1714
1715
            if ($link && $link->getVisibility() == ResourceLink::VISIBILITY_PUBLISHED) {
1716
                return true;
1717
            }
1718
1719
            return false;
1720
1721
            // 4.1 Checking document visibility for a Course
1722
            if ($session_id == 0) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

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