Passed
Push — master ( 2a9d43...0c1a02 )
by Julito
09:45
created

Template::key()   A

Complexity

Conditions 6
Paths 24

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 11
nc 24
nop 1
dl 0
loc 17
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
6
use Chamilo\CoreBundle\Framework\Container;
7
use Chamilo\UserBundle\Entity\User;
8
use Symfony\Component\HttpFoundation\Response;
9
10
/**
11
 * Class Template.
12
 *
13
 * @author Julio Montoya <[email protected]>
14
 *
15
 * @todo better organization of the class, methods and variables
16
 */
17
class Template
18
{
19
    /**
20
     * The Template folder name see main/template.
21
     *
22
     * @var string
23
     */
24
    public $templateFolder = 'default';
25
26
    /**
27
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
28
     * This variable is set from the database.
29
     *
30
     * @var string
31
     */
32
    public $theme = '';
33
34
    /**
35
     * @var string
36
     */
37
    public $preview_theme = '';
38
    public $title = null;
39
    public $show_header;
40
    public $show_footer;
41
    public $help;
42
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
43
    public $show_learnpath = false; // This is a learnpath section or not?
44
    public $plugin = null;
45
    public $course_id = null;
46
    public $user_is_logged_in = false;
47
    public $twig = null;
48
49
    /* Loads chamilo plugins */
50
    public $load_plugins = false;
51
    public $params = [];
52
    public $force_plugin_load = false;
53
    public $responseCode = 0;
54
    private $themeDir;
55
56
    /**
57
     * @param string $title
58
     * @param bool   $show_header
59
     * @param bool   $show_footer
60
     * @param bool   $show_learnpath
61
     * @param bool   $hide_global_chat
62
     * @param bool   $load_plugins
63
     * @param int    $responseCode
64
     * @param bool   $sendHeaders      send http headers or not
65
     */
66
    public function __construct(
67
        $title = '',
68
        $show_header = true,
0 ignored issues
show
Unused Code introduced by
The parameter $show_header is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

68
        /** @scrutinizer ignore-unused */ $show_header = true,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
69
        $show_footer = true,
0 ignored issues
show
Unused Code introduced by
The parameter $show_footer is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

69
        /** @scrutinizer ignore-unused */ $show_footer = true,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
70
        $show_learnpath = false,
71
        $hide_global_chat = false,
72
        $load_plugins = true,
73
        $sendHeaders = true,
0 ignored issues
show
Unused Code introduced by
The parameter $sendHeaders is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

73
        /** @scrutinizer ignore-unused */ $sendHeaders = true,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
74
        $responseCode = 0
0 ignored issues
show
Unused Code introduced by
The parameter $responseCode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

74
        /** @scrutinizer ignore-unused */ $responseCode = 0

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
75
    ) {
76
        // Page title
77
        $this->title = $title;
78
        global $interbreadcrumb;
79
        $interbreadcrumb[] = ['url' => '#', 'name' => $title];
80
        $this->show_learnpath = $show_learnpath;
81
        //$this->setResponseCode($responseCode);
82
83
        if (empty($this->show_learnpath)) {
84
            $origin = api_get_origin();
85
            if ($origin === 'learnpath') {
86
                $this->show_learnpath = true;
87
                $show_footer = false;
88
                $show_header = false;
89
            }
90
        }
91
        $this->hide_global_chat = $hide_global_chat;
0 ignored issues
show
Bug Best Practice introduced by
The property hide_global_chat does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
92
        $this->load_plugins = $load_plugins;
93
94
        /*$template_paths = [
95
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
96
            api_get_path(SYS_CODE_PATH).'template', //template folder
97
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
98
            api_get_path(SYS_PATH).'src/ThemeBundle/Resources/views',
99
        ];*/
100
101
        $this->twig = Container::getTwig();
102
103
        // Setting system variables
104
        //$this->set_system_parameters();
105
106
        // Setting user variables
107
        //$this->set_user_parameters();
108
109
        // Setting course variables
110
        //$this->set_course_parameters();
111
112
        // Setting administrator variables
113
        //$this->setAdministratorParams();
114
        //$this->setCSSEditor();
115
116
        // Header and footer are showed by default
117
        //$this->set_footer($show_footer);
118
        //$this->set_header($show_header);
119
120
        //$this->set_header_parameters($sendHeaders);
121
        //$this->set_footer_parameters();
122
123
        $defaultStyle = api_get_setting('display.default_template');
124
        if (!empty($defaultStyle)) {
125
            $this->templateFolder = $defaultStyle;
126
        }
127
    }
128
129
    /**
130
     * @param string $helpInput
131
     */
132
    public function setHelp($helpInput = null)
133
    {
134
        if (!empty($helpInput)) {
135
            $help = $helpInput;
136
        } else {
137
            $help = $this->help;
138
        }
139
140
        $content = '';
141
        if (api_get_setting('enable_help_link') == 'true') {
142
            if (!empty($help)) {
143
                $help = Security::remove_XSS($help);
144
                $content = '<div class="help">';
145
                $content .= Display::url(
146
                    Display::return_icon('help.png', get_lang('Help'), null, ICON_SIZE_LARGE),
147
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
148
                    [
149
                        'class' => 'ajax',
150
                        'data-title' => get_lang('Help'),
151
                    ]
152
                );
153
                $content .= '</div>';
154
            }
155
        }
156
        $this->assign('help_content', $content);
157
    }
158
159
    /**
160
     * Use template system to parse the actions menu.
161
     *
162
     * @todo finish it!
163
     */
164
    public function set_actions($actions)
165
    {
166
        $action_string = '';
167
        if (!empty($actions)) {
168
            foreach ($actions as $action) {
169
                $action_string .= $action;
170
            }
171
        }
172
        $this->assign('actions', $actions);
173
    }
174
175
    /**
176
     * Render the template.
177
     *
178
     * @param string $template           The template path
179
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
180
     */
181
    public function display($template)
182
    {
183
        $template = str_replace('tpl', 'html.twig', $template);
184
        $templateFile = api_get_path(SYS_CODE_PATH).'template/'.$template;
185
186
        $this->loadLegacyParams();
187
188
        if (!file_exists($templateFile)) {
189
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
190
            echo $e->getMessage();
191
            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...
192
        }
193
194
        $this->returnResponse($this->params, $template);
195
    }
196
197
    /**
198
     * @param string $template
199
     *
200
     * @throws \Twig\Error\Error
201
     */
202
    public function displayTemplate($template)
203
    {
204
        $this->loadLegacyParams();
205
        $this->returnResponse($this->params, $template);
206
    }
207
208
    /**
209
     * Shortcut to display a 1 col layout (index.php).
210
     * */
211
    public function display_one_col_template()
212
    {
213
        $this->loadLegacyParams();
214
        $template = '@ChamiloTheme/Layout/layout_one_col.html.twig';
215
        $origin = api_get_origin();
216
        if ('learnpath' === $origin) {
217
            $template = '@ChamiloTheme/Layout/no_layout.html.twig';
218
        }
219
        $this->returnResponse($this->params, $template);
220
    }
221
222
    /**
223
     * Displays an empty template.
224
     */
225
    public function display_blank_template()
226
    {
227
        $this->loadLegacyParams();
228
        $template = '@ChamiloTheme/Layout/blank.html.twig';
229
        $this->returnResponse($this->params, $template);
230
    }
231
232
    /**
233
     * Displays an empty template.
234
     */
235
    public function displayBlankTemplateNoHeader()
236
    {
237
        $this->loadLegacyParams();
238
        $template = '@ChamiloTheme/Layout/blank_no_header.html.twig';
239
        $this->returnResponse($this->params, $template);
240
    }
241
242
    /**
243
     * Displays an empty template.
244
     */
245
    public function display_no_layout_template()
246
    {
247
        $this->loadLegacyParams();
248
        $template = '@ChamiloTheme/Layout/no_layout.html.twig';
249
        $this->returnResponse($this->params, $template);
250
    }
251
252
    /**
253
     * Displays an empty template.
254
     */
255
    public function displaySkillLayout()
256
    {
257
        $this->loadLegacyParams();
258
        $template = '@ChamiloTheme/Layout/skill_layout.html.twig';
259
        $this->returnResponse($this->params, $template);
260
    }
261
262
    /**
263
     * return true if toolbar has to be displayed for user.
264
     *
265
     * @return bool
266
     */
267
    public static function isToolBarDisplayedForUser()
268
    {
269
        //Toolbar
270
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
271
        $show_toolbar = false;
272
273
        switch ($show_admin_toolbar) {
274
            case 'do_not_show':
275
                break;
276
            case 'show_to_admin':
277
                if (api_is_platform_admin()) {
278
                    $show_toolbar = true;
279
                }
280
                break;
281
            case 'show_to_admin_and_teachers':
282
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
283
                    $show_toolbar = true;
284
                }
285
                break;
286
            case 'show_to_all':
287
                $show_toolbar = true;
288
                break;
289
        }
290
291
        return $show_toolbar;
292
    }
293
294
    /**
295
     * Sets the header visibility.
296
     *
297
     * @param bool true if we show the header
298
     */
299
    public function set_header($status)
300
    {
301
        $this->show_header = $status;
302
        $this->assign('show_header', $status);
303
304
        $show_toolbar = 0;
305
306
        if (self::isToolBarDisplayedForUser()) {
307
            $show_toolbar = 1;
308
        }
309
310
        $this->assign('show_toolbar', $show_toolbar);
311
312
        // Only if course is available
313
        $courseToolBar = '';
314
        $show_course_navigation_menu = '';
315
        if (!empty($this->course_id) && $this->user_is_logged_in) {
316
            if (api_get_setting('show_toolshortcuts') !== 'false') {
317
                // Course toolbar
318
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
319
            }
320
            if (api_get_setting('show_navigation_menu') !== 'false') {
321
                //Course toolbar
322
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
323
            }
324
        }
325
        $this->assign('show_course_shortcut', $courseToolBar);
326
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
327
    }
328
329
    /**
330
     * Returns the sub-folder and filename for the given tpl file.
331
     *
332
     * If template not found in overrides/ or custom template folder, the default template will be used.
333
     *
334
     * @param string $name
335
     *
336
     * @return string
337
     */
338
    public static function findTemplateFilePath($name)
339
    {
340
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
341
342
        // Check if the tpl file is present in the main/template/overrides/ dir
343
        // Overrides is a special directory meant for temporary template
344
        // customization. It must be taken into account before anything else
345
        if (is_readable($sysTemplatePath."overrides/$name")) {
346
            return "overrides/$name";
347
        }
348
349
        $defaultFolder = api_get_configuration_value('default_template');
350
351
        // If a template folder has been manually defined, search for the right
352
        // file, and if not found, go for the same file in the default template
353
        if ($defaultFolder && $defaultFolder != 'default') {
354
            // Avoid missing template error, use the default file.
355
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
356
                return "$defaultFolder/$name";
357
            }
358
        }
359
360
        $name = str_replace('tpl', 'html.twig', $name);
361
362
        return "default/$name";
363
    }
364
365
    /**
366
     * Call non-static for Template::findTemplateFilePath.
367
     *
368
     * @see Template::findTemplateFilePath()
369
     *
370
     * @param string $name
371
     *
372
     * @return string
373
     */
374
    public function get_template($name)
375
    {
376
        return api_find_template($name);
377
    }
378
379
    /**
380
     * Get CSS themes sub-directory.
381
     *
382
     * @param string $theme
383
     *
384
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
385
     */
386
    public static function getThemeDir($theme)
387
    {
388
        $themeDir = 'themes/'.$theme.'/';
389
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
390
        if (!empty($virtualTheme)) {
391
            $virtualThemeList = api_get_themes(true);
392
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
393
            if ($isVirtualTheme) {
394
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
395
            }
396
        }
397
398
        return $themeDir;
399
    }
400
401
    /**
402
     * Set system parameters from api_get_configuration into _s array for use in TPLs
403
     * Also fills the _p array from getWebPaths().
404
     *
405
     * @uses \self::getWebPaths()
406
     */
407
    public function set_system_parameters()
408
    {
409
        $this->theme = api_get_visual_theme();
410
        if (!empty($this->preview_theme)) {
411
            $this->theme = $this->preview_theme;
412
        }
413
414
        $this->assign('theme', $this->theme);
415
416
        $this->themeDir = self::getThemeDir($this->theme);
417
418
        // Setting app paths/URLs
419
        //$this->assign('_p', $this->getWebPaths());
420
421
        // Here we can add system parameters that can be use in any template
422
        $_s = [
423
            'software_name' => api_get_configuration_value('software_name'),
424
            'system_version' => api_get_configuration_value('system_version'),
425
            'site_name' => api_get_setting('siteName'),
426
            'institu_tion' => api_get_setting('Institution'),
427
            'date' => api_format_date('now', DATE_FORMAT_LONG),
428
            'timezone' => api_get_timezone(),
429
            'gamification_mode' => api_get_setting('gamification_mode'),
430
        ];
431
        $this->assign('_s', $_s);
432
    }
433
434
    /**
435
     * Set legacy twig globals in order to be hook in the LegacyListener.php.
436
     *
437
     * @return array
438
     */
439
    public static function getGlobals()
440
    {
441
        $queryString = empty($_SERVER['QUERY_STRING']) ? '' : $_SERVER['QUERY_STRING'];
442
        $requestURI = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
443
444
        /*$_p = [
445
            'web' => api_get_path(WEB_PATH),
446
            'web_relative' => api_get_path(REL_PATH),
447
            'web_course' => api_get_path(WEB_COURSE_PATH),
448
            'web_main' => api_get_path(WEB_CODE_PATH),
449
            'web_css' => api_get_path(WEB_CSS_PATH),
450
            //'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
451
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
452
            'web_img' => api_get_path(WEB_IMG_PATH),
453
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
454
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
455
            'web_self' => api_get_self(),
456
            'web_self_query_vars' => api_htmlentities($requestURI),
457
            'web_cid_query' => api_get_cidreq(),
458
        ];*/
459
        $_s = [
460
            'software_name' => api_get_configuration_value('software_name'),
461
            'system_version' => api_get_configuration_value('system_version'),
462
            'site_name' => api_get_setting('siteName'),
463
            'institution' => api_get_setting('Institution'),
464
            //'date' => api_format_date('now', DATE_FORMAT_LONG),
465
            'date' => '',
466
            'timezone' => '',
467
            //'timezone' => api_get_timezone(),
468
            'gamification_mode' => api_get_setting('gamification_mode'),
469
        ];
470
471
        //$user_info = api_get_user_info();
472
473
        return [
474
            '_s' => $_s,
475
            //       '_u' => $user_info,
476
            'template' => 'default', // @todo setup template folder in config.yml;
477
        ];
478
    }
479
480
    /**
481
     * Set theme, include mainstream CSS files.
482
     *
483
     * @deprecated
484
     * @see setCssCustomFiles() for additional CSS sheets
485
     */
486
    public function setCssFiles()
487
    {
488
        global $disable_js_and_css_files;
489
        $css = [];
490
491
        // Default CSS Bootstrap
492
        $bowerCSSFiles = [
493
            'fontawesome/css/font-awesome.min.css',
494
            'jquery-ui/themes/smoothness/theme.css',
495
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
496
            'mediaelement/build/mediaelementplayer.min.css',
497
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
498
            'bootstrap/dist/css/bootstrap.min.css',
499
            'jquery.scrollbar/jquery.scrollbar.css',
500
            //'bootstrap-daterangepicker/daterangepicker.css',
501
            'bootstrap-select/dist/css/bootstrap-select.min.css',
502
            'select2/dist/css/select2.min.css',
503
            'flag-icon-css/css/flag-icon.min.css',
504
            'mediaelement/plugins/vrview/vrview.css',
505
        ];
506
507
        $features = api_get_configuration_value('video_features');
508
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen', 'vrview'];
509
510
        if (!empty($features) && isset($features['features'])) {
511
            foreach ($features['features'] as $feature) {
512
                if ($feature === 'vrview') {
513
                    continue;
514
                }
515
                $bowerCSSFiles[] = "mediaelement/plugins/$feature/$feature.css";
516
                $defaultFeatures[] = $feature;
517
            }
518
        }
519
520
        foreach ($bowerCSSFiles as $file) {
521
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
522
        }
523
524
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
525
526
        if (api_is_global_chat_enabled()) {
527
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
528
        }
529
        $css_file_to_string = '';
530
        foreach ($css as $file) {
531
            $css_file_to_string .= api_get_css($file);
532
        }
533
534
        if (!$disable_js_and_css_files) {
535
            $this->assign('css_static_file_to_string', $css_file_to_string);
536
        }
537
538
        $defaultFeatures = implode("','", $defaultFeatures);
539
        $this->assign('video_features', $defaultFeatures);
540
    }
541
542
    /**
543
     * Prepare custom CSS to be added at the very end of the <head> section.
544
     *
545
     * @see setCssFiles() for the mainstream CSS files
546
     */
547
    public function setCssCustomFiles()
548
    {
549
        global $disable_js_and_css_files;
550
        $css = [];
551
        if ($this->show_learnpath) {
552
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
553
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
554
            }
555
        }
556
557
        $css_file_to_string = '';
558
        foreach ($css as $file) {
559
            $css_file_to_string .= api_get_css($file);
560
        }
561
562
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
563
        if (SHOW_TEXT_NEAR_ICONS == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
564
            //hack in order to fix the actions buttons
565
            $css_file_to_string .= '<style>
566
                .td_actions a {
567
                    float:left;
568
                    width:100%;
569
                }
570
                .forum_message_left a {
571
                    float:left;
572
                    width:100%;
573
                }
574
                </style>';
575
        }
576
577
        $navigator_info = api_get_navigator();
578
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
579
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
580
        }
581
582
        if (!$disable_js_and_css_files) {
583
            $this->assign('css_custom_file_to_string', $css_file_to_string);
584
585
            $style_print = '';
586
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
587
                $style_print = api_get_css(
588
                    api_get_path(WEB_CSS_PATH).$this->theme.'/print.css',
589
                    'print'
590
                );
591
            }
592
            $this->assign('css_style_print', $style_print);
593
        }
594
595
        // Logo
596
        $logo = return_logo($this->theme);
597
        $logoPdf = return_logo($this->theme, false);
598
        $this->assign('logo', $logo);
599
        $this->assign('logo_pdf', $logoPdf);
600
        $this->assign('show_media_element', 1);
601
    }
602
603
    /**
604
     * Declare and define the template variable that will be used to load
605
     * javascript libraries in the header.
606
     */
607
    public function set_js_files()
608
    {
609
        global $disable_js_and_css_files, $htmlHeadXtra;
610
        $isoCode = api_get_language_isocode();
611
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
612
613
        if ($isoCode == 'en') {
614
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
615
        }
616
        // JS files
617
        $js_files = [
618
            'chosen/chosen.jquery.min.js',
619
        ];
620
621
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
622
623
        if (api_is_global_chat_enabled() || $viewBySession) {
624
            // Do not include the global chat in LP
625
            if ($this->show_learnpath == false &&
626
                $this->show_footer == true &&
627
                $this->hide_global_chat == false
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
628
            ) {
629
                $js_files[] = 'chat/js/chat.js';
630
            }
631
        }
632
633
        if (api_get_setting('accessibility_font_resize') === 'true') {
634
            $js_files[] = 'fontresize.js';
635
        }
636
637
        $js_file_to_string = '';
638
        $bowerJsFiles = [
639
            'modernizr/modernizr.js',
640
            'jquery/query.min.js',
641
            'bootstrap/dist/js/bootstrap.min.js',
642
            'jquery-ui/jquery-ui.min.js',
643
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
644
            'moment/min/moment-with-locales.js',
645
            //'bootstrap-daterangepicker/daterangepicker.js',
646
            'jquery-timeago/jquery.timeago.js',
647
            'mediaelement/mediaelement-and-player.min.js',
648
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
649
            'image-map-resizer/js/imageMapResizer.min.js',
650
            'jquery.scrollbar/jquery.scrollbar.min.js',
651
            //'readmore-js/readmore.min.js',
652
            'bootstrap-select/dist/js/bootstrap-select.min.js',
653
            $selectLink,
654
            'select2/dist/js/select2.min.js',
655
            "select2/dist/js/i18n/$isoCode.js",
656
            'mediaelement/plugins/vrview/vrview.js',
657
        ];
658
659
        $features = api_get_configuration_value('video_features');
660
        if (!empty($features) && isset($features['features'])) {
661
            foreach ($features['features'] as $feature) {
662
                if ($feature === 'vrview') {
663
                    continue;
664
                }
665
                $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js";
666
            }
667
        }
668
669
        if (CHAMILO_LOAD_WYSIWYG === true) {
670
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
671
        }
672
673
        if (api_get_setting('include_asciimathml_script') === 'true') {
674
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
675
        }
676
677
        if ($isoCode != 'en') {
678
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
679
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
680
        }
681
682
        foreach ($bowerJsFiles as $file) {
683
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
684
        }
685
686
        foreach ($js_files as $file) {
687
            //$js_file_to_string .= api_get_js($file);
688
        }
689
690
        // Loading email_editor js
691
        if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') {
692
            $template = $this->get_template('mail_editor/email_link.js.tpl');
693
            $js_file_to_string .= $this->fetch($template);
694
        }
695
696
        if (!$disable_js_and_css_files) {
697
            $this->assign('js_file_to_string', $js_file_to_string);
698
            $extraHeaders = '';
699
            //$extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
700
            //Adding jquery ui by default
701
            $extraHeaders .= api_get_jquery_ui_js();
702
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
703
                foreach ($htmlHeadXtra as &$this_html_head) {
704
                    $extraHeaders .= $this_html_head."\n";
705
                }
706
            }
707
708
            $ajax = api_get_path(WEB_AJAX_PATH);
709
            $courseId = api_get_course_id();
710
            if (empty($courseId)) {
711
                $courseLogoutCode = '
712
                <script>
713
                function courseLogout() {
714
                }
715
                </script>';
716
            } else {
717
                $courseLogoutCode = "
718
                <script>
719
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
720
                function courseLogout() {
721
                    $.ajax({
722
                        async : false,
723
                        url: logOutUrl,
724
                        success: function (data) {
725
                            return 1;
726
                        }
727
                    });
728
                }
729
                </script>";
730
            }
731
732
            $extraHeaders .= $courseLogoutCode;
733
            $this->assign('extra_headers', $extraHeaders);
734
        }
735
    }
736
737
    /**
738
     * @param array  $params
739
     * @param string $template
740
     *
741
     * @throws \Twig\Error\Error
742
     */
743
    public function returnResponse($params, $template)
744
    {
745
        $flash = Display::getFlashToString();
746
        Display::cleanFlashMessages();
747
        $response = new Response();
748
        $params['flash_messages'] = $flash;
749
        $content = Container::getTemplating()->render($template, $params);
750
        $response->setContent($content);
751
        $response->send();
752
    }
753
754
    /**
755
     * Special function to declare last-minute JS libraries which depend on
756
     * other things to be declared first. In particular, it might be useful
757
     * under IE9 with compatibility mode, which for some reason is getting
758
     * upset when a variable is used in a function (even if not used yet)
759
     * when this variable hasn't been defined yet.
760
     */
761
    public function set_js_files_post()
762
    {
763
        global $disable_js_and_css_files;
764
        $js_files = [];
765
        if (api_is_global_chat_enabled()) {
766
            //Do not include the global chat in LP
767
            if ($this->show_learnpath == false && $this->show_footer == true && $this->hide_global_chat == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
768
                $js_files[] = 'chat/js/chat.js';
769
            }
770
        }
771
        $js_file_to_string = '';
772
        foreach ($js_files as $js_file) {
773
            $js_file_to_string .= api_get_js($js_file);
774
        }
775
        if (!$disable_js_and_css_files) {
776
            $this->assign('js_file_to_string_post', $js_file_to_string);
777
        }
778
    }
779
780
    /**
781
     * @param string $theme
782
     *
783
     * @return string
784
     */
785
    public static function getPortalIcon($theme)
786
    {
787
        // Default root chamilo favicon
788
        $icon = 'favicon.ico';
789
790
        // Added to verify if in the current Chamilo Theme exist a favicon
791
        $themeUrl = api_get_path(SYS_CSS_PATH).'themes/'.$theme.'/images/';
792
793
        // If exist pick the current chamilo theme favicon.
794
        if (is_file($themeUrl.'favicon.ico')) {
795
            $icon = 'build/css/themes/'.$theme.'/images/favicon.ico';
796
        }
797
798
        return $icon;
799
    }
800
801
    /**
802
     * Show footer js template.
803
     */
804
    public function show_footer_js_template()
805
    {
806
        $tpl = $this->get_template('layout/footer.js.tpl');
807
        $this->display($tpl);
808
    }
809
810
    /**
811
     * @param string $template
812
     *
813
     * @return string
814
     */
815
    public function fetch($template = null)
816
    {
817
        return $this->twig->render($template, $this->params);
818
    }
819
820
    /**
821
     * @param string $variable
822
     * @param mixed  $value
823
     */
824
    public function assign($variable, $value = '')
825
    {
826
        $this->params[$variable] = $value;
827
    }
828
829
    /**
830
     * Adds a body class for login pages.
831
     */
832
    public function setLoginBodyClass()
833
    {
834
        $this->assign('login_class', 'section-login');
835
    }
836
837
    /**
838
     * The theme that will be used if the database is not working.
839
     *
840
     * @return string
841
     */
842
    public static function getThemeFallback()
843
    {
844
        $theme = api_get_configuration_value('theme_fallback');
845
        if (empty($theme)) {
846
            $theme = 'chamilo';
847
        }
848
849
        return $theme;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $theme also could return the type boolean which is incompatible with the documented return type string.
Loading history...
850
    }
851
852
    /**
853
     * @return string
854
     */
855
    public function handleLoginFailed()
856
    {
857
        $message = get_lang('Login failed - incorrect login or password.');
858
859
        if (!isset($_GET['error'])) {
860
            if (api_is_self_registration_allowed()) {
861
                $message = get_lang('Login failed - if you are not registered, you can do so using the <a href=claroline/auth/inscription.php>registration form</a>');
862
            }
863
        } else {
864
            switch ($_GET['error']) {
865
                case '':
866
                    if (api_is_self_registration_allowed()) {
867
                        $message = get_lang('Login failed - if you are not registered, you can do so using the <a href=claroline/auth/inscription.php>registration form</a>');
868
                    }
869
                    break;
870
                case 'account_expired':
871
                    $message = get_lang('Account expired');
872
                    break;
873
                case 'account_inactive':
874
                    $message = get_lang('Account inactive');
875
876
                    if (api_get_setting('allow_registration') === 'confirmation') {
877
                        $message = get_lang('Your account is inactive because you have not confirmed it yet. Check your email and follow the instructions or click the following link to resend the email').PHP_EOL;
878
                        $message .= Display::url(
879
                            get_lang('Send confirmation mail again'),
880
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
881
                            ['class' => 'alert-link']
882
                        );
883
                    }
884
                    break;
885
                case 'user_password_incorrect':
886
                    $message = get_lang('Login failed - incorrect login or password.');
887
                    break;
888
                case 'access_url_inactive':
889
                    $message = get_lang('Account inactive for this URL');
890
                    break;
891
                case 'wrong_captcha':
892
                    $message = get_lang('The text you entered doesn\'t match the picture.');
893
                    break;
894
                case 'blocked_by_captcha':
895
                    $message = get_lang('Account blocked by captcha.');
896
                    break;
897
                case 'multiple_connection_not_allowed':
898
                    $message = get_lang('This user is already logged in');
899
                    break;
900
            }
901
        }
902
903
        return Display::return_message($message, 'error', false);
904
    }
905
906
    /**
907
     * @return string
908
     */
909
    public function displayLoginForm()
910
    {
911
        $form = new FormValidator(
912
            'form-login',
913
            'POST',
914
            api_get_path(WEB_PUBLIC_PATH).'login_check',
915
            null,
916
            null,
917
            FormValidator::LAYOUT_BOX_NO_LABEL
918
        );
919
        $params = [
920
            'id' => '_username',
921
            'autofocus' => 'autofocus',
922
            'icon' => 'user fa-fw',
923
            'placeholder' => get_lang('Username'),
924
        ];
925
        $browserAutoCapitalize = false;
926
        // Avoid showing the autocapitalize option if the browser doesn't
927
        // support it: this attribute is against the HTML5 standard
928
        if (api_browser_support('autocapitalize')) {
0 ignored issues
show
Deprecated Code introduced by
The function api_browser_support() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

928
        if (/** @scrutinizer ignore-deprecated */ api_browser_support('autocapitalize')) {
Loading history...
929
            $browserAutoCapitalize = false;
930
            $params['autocapitalize'] = 'none';
931
        }
932
        $form->addText(
933
            '_username',
934
            get_lang('Username'),
935
            true,
936
            $params
937
        );
938
        $params = [
939
            'id' => '_password',
940
            'icon' => 'lock fa-fw',
941
            'placeholder' => get_lang('Pass'),
942
        ];
943
        if ($browserAutoCapitalize) {
944
            $params['autocapitalize'] = 'none';
945
        }
946
        $form->addElement(
947
            'password',
948
            '_password',
949
            get_lang('Pass'),
950
            $params
951
        );
952
953
        $token = Chamilo\CoreBundle\Framework\Container::$container->get('security.csrf.token_manager')->getToken('authenticate');
954
        $form->addHidden('_csrf_token', $token->getValue());
955
956
        // Captcha
957
        $captcha = api_get_setting('allow_captcha');
958
        $allowCaptcha = $captcha === 'true';
959
960
        if ($allowCaptcha) {
961
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
962
            if ($useCaptcha) {
963
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
964
                $options = [
965
                    'width' => 250,
966
                    'height' => 90,
967
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
968
                    'sessionVar' => basename(__FILE__, '.php'),
969
                    'imageOptions' => [
970
                        'font_size' => 20,
971
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
972
                        'font_file' => 'OpenSans-Regular.ttf',
973
                        //'output' => 'gif'
974
                    ],
975
                ];
976
977
                // Minimum options using all defaults (including defaults for Image_Text):
978
                //$options = array('callback' => 'qfcaptcha_image.php');
979
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
980
                $form->addHtml(get_lang('Click on the image to load a new one.'));
981
982
                $form->addElement(
983
                    'text',
984
                    'captcha',
985
                    get_lang('Enter the letters you see.')
986
                );
987
                $form->addRule(
988
                    'captcha',
989
                    get_lang('Enter the characters you see on the image'),
990
                    'required',
991
                    null,
992
                    'client'
993
                );
994
                $form->addRule(
995
                    'captcha',
996
                    get_lang('The text you entered doesn\'t match the picture.'),
997
                    'CAPTCHA',
998
                    $captcha_question
999
                );
1000
            }
1001
        }
1002
1003
        $form->addButton(
1004
            'submitAuth',
1005
            get_lang('Login'),
1006
            null,
1007
            'primary',
1008
            null,
1009
            'btn-block'
1010
        );
1011
1012
        $html = $form->returnForm();
1013
1014
        return $html;
1015
    }
1016
1017
    /**
1018
     * Returns the tutors names for the current course in session
1019
     * Function to use in Twig templates.
1020
     *
1021
     * @return string
1022
     */
1023
    public static function returnTutorsNames()
1024
    {
1025
        $em = Database::getManager();
1026
        $tutors = $em
1027
            ->createQuery('
1028
                SELECT u FROM ChamiloUserBundle:User u
1029
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1030
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1031
            ')
1032
            ->setParameters([
1033
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1034
                'session' => api_get_session_id(),
1035
                'course' => api_get_course_int_id(),
1036
            ])
1037
            ->getResult();
1038
1039
        $names = [];
1040
1041
        /** @var User $tutor */
1042
        foreach ($tutors as $tutor) {
1043
            $names[] = UserManager::formatUserFullName($tutor);
1044
        }
1045
1046
        return implode(CourseManager::USER_SEPARATOR, $names);
1047
    }
1048
1049
    /*s
1050
     * Returns the teachers name for the current course
1051
     * Function to use in Twig templates
1052
     * @return string
1053
     */
1054
    public static function returnTeachersNames()
1055
    {
1056
        $em = Database::getManager();
1057
        $teachers = $em
1058
            ->createQuery('
1059
                SELECT u FROM ChamiloUserBundle:User u
1060
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1061
                WHERE cu.status = :teacher_status AND cu.course = :course
1062
            ')
1063
            ->setParameters([
1064
                'teacher_status' => User::COURSE_MANAGER,
1065
                'course' => api_get_course_int_id(),
1066
            ])
1067
            ->getResult();
1068
1069
        $names = [];
1070
1071
        /** @var User $teacher */
1072
        foreach ($teachers as $teacher) {
1073
            $names[] = UserManager::formatUserFullName($teacher);
1074
        }
1075
1076
        return implode(CourseManager::USER_SEPARATOR, $names);
1077
    }
1078
1079
    /**
1080
     * @param int $code
1081
     */
1082
    public function setResponseCode($code)
1083
    {
1084
        $this->responseCode = $code;
1085
    }
1086
1087
    /**
1088
     * @param string $code
1089
     */
1090
    public function getResponseCode()
1091
    {
1092
        return $this->responseCode;
1093
    }
1094
1095
    /**
1096
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1097
     *
1098
     * @return bool Always return true because there is always a string, even if empty
1099
     */
1100
    public function assignBugNotification()
1101
    {
1102
        //@todo move this in the template
1103
        $rightFloatMenu = '';
1104
        $iconBug = Display::return_icon(
1105
            'bug.png',
1106
            get_lang('Report a bug'),
1107
            [],
1108
            ICON_SIZE_LARGE
1109
        );
1110
        if (api_get_setting('show_link_bug_notification') === 'true' && $this->user_is_logged_in) {
1111
            $rightFloatMenu = '<div class="report">
1112
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1113
                    '.$iconBug.'
1114
                </a>
1115
		        </div>';
1116
        }
1117
1118
        if (api_get_setting('show_link_ticket_notification') === 'true' &&
1119
            $this->user_is_logged_in
1120
        ) {
1121
            // by default is project_id = 1
1122
            $defaultProjectId = 1;
1123
            $iconTicket = Display::return_icon(
1124
                'help.png',
1125
                get_lang('Ticket'),
1126
                [],
1127
                ICON_SIZE_LARGE
1128
            );
1129
            $courseInfo = api_get_course_info();
1130
            $courseParams = '';
1131
            if (!empty($courseInfo)) {
1132
                $courseParams = api_get_cidreq();
1133
            }
1134
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams;
1135
1136
            $allow = TicketManager::userIsAllowInProject(api_get_user_info(), $defaultProjectId);
0 ignored issues
show
Bug introduced by
It seems like api_get_user_info() can also be of type false; however, parameter $userInfo of TicketManager::userIsAllowInProject() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1136
            $allow = TicketManager::userIsAllowInProject(/** @scrutinizer ignore-type */ api_get_user_info(), $defaultProjectId);
Loading history...
1137
1138
            if ($allow) {
1139
                $rightFloatMenu .= '<div class="help">
1140
                    <a href="'.$url.'" target="_blank">
1141
                        '.$iconTicket.'
1142
                    </a>
1143
                </div>';
1144
            }
1145
        }
1146
1147
        $this->assign('bug_notification', $rightFloatMenu);
1148
1149
        return true;
1150
    }
1151
1152
    /**
1153
     * Load legacy params.
1154
     */
1155
    private function loadLegacyParams()
1156
    {
1157
        // Set legacy breadcrumb
1158
        global $interbreadcrumb;
1159
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
1160
1161
        global $htmlHeadXtra;
1162
        $this->params['legacy_javascript'] = $htmlHeadXtra;
1163
    }
1164
1165
    /**
1166
     * Prepare the _c array for template files. The _c array contains
1167
     * information about the current course.
1168
     */
1169
    private function set_course_parameters()
0 ignored issues
show
Unused Code introduced by
The method set_course_parameters() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1170
    {
1171
        //Setting course id
1172
        $course = api_get_course_info();
1173
        if (empty($course)) {
1174
            $this->assign('course_is_set', false);
1175
1176
            return;
1177
        }
1178
        $this->assign('course_is_set', true);
1179
        $this->course_id = $course['id'];
1180
        $_c = [
1181
            'id' => $course['real_id'],
1182
            'code' => $course['code'],
1183
            'title' => $course['name'],
1184
            'visibility' => $course['visibility'],
1185
            'language' => $course['language'],
1186
            'directory' => $course['directory'],
1187
            'session_id' => api_get_session_id(),
1188
            'user_is_teacher' => api_is_course_admin(),
1189
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
1190
        ];
1191
        $this->assign('course_code', $course['code']);
1192
        $this->assign('_c', $_c);
1193
    }
1194
1195
    /**
1196
     * Prepare the _u array for template files. The _u array contains
1197
     * information about the current user, as returned by
1198
     * api_get_user_info().
1199
     */
1200
    private function set_user_parameters()
0 ignored issues
show
Unused Code introduced by
The method set_user_parameters() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1201
    {
1202
        $user_info = [];
1203
        $user_info['logged'] = 0;
1204
        $this->user_is_logged_in = false;
1205
        if (api_user_is_login()) {
1206
            $user_info = api_get_user_info(api_get_user_id(), true);
1207
            $user_info['logged'] = 1;
1208
1209
            $user_info['is_admin'] = 0;
1210
            if (api_is_platform_admin()) {
1211
                $user_info['is_admin'] = 1;
1212
            }
1213
1214
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1215
            $this->user_is_logged_in = true;
1216
        }
1217
        // Setting the $_u array that could be use in any template
1218
        $this->assign('_u', $user_info);
1219
    }
1220
1221
    /**
1222
     * Set header parameters.
1223
     *
1224
     * @deprecated
1225
     *
1226
     * @param bool $sendHeaders send headers
1227
     */
1228
    private function set_header_parameters($sendHeaders)
0 ignored issues
show
Unused Code introduced by
The method set_header_parameters() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1229
    {
1230
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1231
        $_course = api_get_course_info();
1232
        $nameTools = $this->title;
1233
        $navigation = return_navigation_array();
1234
        $this->menu_navigation = $navigation['menu_navigation'];
1235
1236
        $this->assign('system_charset', api_get_system_encoding());
1237
1238
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1239
            foreach ($httpHeadXtra as &$thisHttpHead) {
1240
                //header($thisHttpHead);
1241
            }
1242
        }
1243
1244
        $this->assign(
1245
            'online_button',
1246
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
1247
        );
1248
        $this->assign(
1249
            'offline_button',
1250
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
1251
        );
1252
1253
        // Get language iso-code for this page - ignore errors
1254
        $this->assign('document_language', api_get_language_isocode());
1255
1256
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1257
1258
        $title_list = [];
1259
1260
        $title_list[] = api_get_setting('Institution');
1261
        $title_list[] = api_get_setting('siteName');
1262
1263
        if (!empty($course_title)) {
1264
            $title_list[] = $course_title;
1265
        }
1266
        if ($nameTools != '') {
1267
            $title_list[] = $nameTools;
1268
        }
1269
1270
        $title_string = '';
1271
        for ($i = 0; $i < count($title_list); $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...
1272
            $title_string .= $title_list[$i];
1273
            if (isset($title_list[$i + 1])) {
1274
                $item = trim($title_list[$i + 1]);
1275
                if (!empty($item)) {
1276
                    $title_string .= ' - ';
1277
                }
1278
            }
1279
        }
1280
1281
        $this->assign('title_string', $title_string);
1282
1283
        // Setting the theme and CSS files
1284
        $this->setCssFiles();
0 ignored issues
show
Deprecated Code introduced by
The function Template::setCssFiles() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1284
        /** @scrutinizer ignore-deprecated */ $this->setCssFiles();
Loading history...
1285
        $this->set_js_files();
1286
        $this->setCssCustomFiles();
1287
1288
        $browser = api_browser_support('check_browser');
0 ignored issues
show
Deprecated Code introduced by
The function api_browser_support() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1288
        $browser = /** @scrutinizer ignore-deprecated */ api_browser_support('check_browser');
Loading history...
1289
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1290
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1291
            $this->assign('browser_specific_head', $browser_head);
1292
        }
1293
1294
        // Implementation of prefetch.
1295
        // See http://cdn.chamilo.org/main/img/online.png for details
1296
        $prefetch = '';
1297
        if (!empty($_configuration['cdn_enable'])) {
1298
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1299
            foreach ($_configuration['cdn'] as $host => $exts) {
1300
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1301
            }
1302
        }
1303
1304
        $this->assign('prefetch', $prefetch);
1305
        $this->assign('text_direction', api_get_text_direction());
1306
        $this->assign('section_name', 'section-'.$this_section);
1307
        $this->assignFavIcon();
1308
        $this->setHelp();
1309
1310
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1311
1312
        $this->assignAccessibilityBlock(); //Prepare the 'accessibility' var for the template
1313
1314
        // Preparing values for the menu
1315
1316
        // Logout link
1317
        $hideLogout = api_get_setting('hide_logout_button');
1318
        if ($hideLogout === 'true') {
1319
            $this->assign('logout_link', null);
1320
        } else {
1321
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1322
        }
1323
1324
        // Profile link
1325
        if (api_get_setting('allow_social_tool') == 'true') {
1326
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1327
        } else {
1328
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1329
        }
1330
1331
        $this->assign('profile_url', $profile_url);
1332
1333
        //Message link
1334
        $message_link = null;
1335
        $message_url = null;
1336
        if (api_get_setting('allow_message_tool') == 'true') {
1337
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1338
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1339
        }
1340
        $this->assign('message_link', $message_link);
1341
        $this->assign('message_url', $message_url);
1342
1343
        $pendingSurveyLink = '';
1344
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1345
        if ($show) {
1346
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1347
        }
1348
        $this->assign('pending_survey_url', $pendingSurveyLink);
1349
1350
        // Certificate Link
1351
        $allow = api_get_configuration_value('certificate.hide_my_certificate_link');
1352
        if ($allow === false) {
1353
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1354
            $certificateLink = Display::url(
1355
                get_lang('My certificates'),
1356
                $certificateUrl
1357
            );
1358
            $this->assign('certificate_link', $certificateLink);
1359
            $this->assign('certificate_url', $certificateUrl);
1360
        }
1361
1362
        $institution = api_get_setting('Institution');
1363
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1364
1365
        $this->assign('portal_name', $portal_name);
1366
1367
        //Menu
1368
        //$menu = menuArray();
1369
        //$this->assign('menu', $menu);
1370
1371
        $breadcrumb = '';
1372
        // Hide breadcrumb in LP
1373
        if ($this->show_learnpath == false) {
1374
            $breadcrumb = return_breadcrumb(
1375
                $interbreadcrumb,
1376
                $language_file,
1377
                $nameTools
1378
            );
1379
        }
1380
        $this->assign('breadcrumb', $breadcrumb);
1381
1382
        //Extra content
1383
        $extra_header = null;
1384
        if (!api_is_platform_admin()) {
1385
            $extra_header = trim(api_get_setting('header_extra_content'));
1386
        }
1387
        $this->assign('header_extra_content', $extra_header);
1388
1389
        if ($sendHeaders) {
1390
            /*header('Content-Type: text/html; charset='.api_get_system_encoding());
1391
            header(
1392
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1393
            );
1394
            self::addHTTPSecurityHeaders();*/
1395
1396
            $responseCode = $this->getResponseCode();
1397
            if (!empty($responseCode)) {
1398
                switch ($responseCode) {
1399
                    case '404':
1400
                        header("HTTP/1.0 404 Not Found");
1401
                        break;
1402
                }
1403
            }
1404
        }
1405
1406
        $socialMeta = '';
1407
        $metaTitle = api_get_setting('meta_title');
1408
        if (!empty($metaTitle)) {
1409
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1410
            $metaSite = api_get_setting('meta_twitter_site');
1411
            if (!empty($metaSite)) {
1412
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1413
                $metaCreator = api_get_setting('meta_twitter_creator');
1414
                if (!empty($metaCreator)) {
1415
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1416
                }
1417
            }
1418
1419
            // The user badge page emits its own meta tags, so if this is
1420
            // enabled, ignore the global ones
1421
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1422
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1423
1424
            if (!$userId && !$skillId) {
1425
                // no combination of user and skill ID has been defined,
1426
                // so print the normal OpenGraph meta tags
1427
                $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1428
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1429
1430
                $metaDescription = api_get_setting('meta_description');
1431
                if (!empty($metaDescription)) {
1432
                    $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1433
                }
1434
1435
                $metaImage = api_get_setting('meta_image_path');
1436
                if (!empty($metaImage)) {
1437
                    if (is_file(api_get_path(SYS_PATH).$metaImage)) {
1438
                        $path = api_get_path(WEB_PATH).$metaImage;
1439
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1440
                    }
1441
                }
1442
            }
1443
        }
1444
1445
        $this->assign('social_meta', $socialMeta);
1446
    }
1447
1448
    /**
1449
     * Set footer parameters.
1450
     */
1451
    private function set_footer_parameters()
0 ignored issues
show
Unused Code introduced by
The method set_footer_parameters() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1452
    {
1453
        // Loading footer extra content
1454
        if (!api_is_platform_admin()) {
1455
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1456
            if (!empty($extra_footer)) {
1457
                $this->assign('footer_extra_content', $extra_footer);
1458
            }
1459
        }
1460
    }
1461
1462
    /**
1463
     * Manage specific HTTP headers security.
1464
     */
1465
    private function addHTTPSecurityHeaders()
0 ignored issues
show
Unused Code introduced by
The method addHTTPSecurityHeaders() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1466
    {
1467
        // Implementation of HTTP headers security, as suggested and checked
1468
        // by https://securityheaders.io/
1469
        // Enable these settings in configuration.php to use them on your site
1470
        // Strict-Transport-Security
1471
        $setting = api_get_configuration_value('security_strict_transport');
1472
        if (!empty($setting)) {
1473
            header('Strict-Transport-Security: '.$setting);
1474
        }
1475
        // Content-Security-Policy
1476
        $setting = api_get_configuration_value('security_content_policy');
1477
        if (!empty($setting)) {
1478
            header('Content-Security-Policy: '.$setting);
1479
        }
1480
        $setting = api_get_configuration_value('security_content_policy_report_only');
1481
        if (!empty($setting)) {
1482
            header('Content-Security-Policy-Report-Only: '.$setting);
1483
        }
1484
        // Public-Key-Pins
1485
        $setting = api_get_configuration_value('security_public_key_pins');
1486
        if (!empty($setting)) {
1487
            header('Public-Key-Pins: '.$setting);
1488
        }
1489
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1490
        if (!empty($setting)) {
1491
            header('Public-Key-Pins-Report-Only: '.$setting);
1492
        }
1493
        // X-Frame-Options
1494
        $setting = api_get_configuration_value('security_x_frame_options');
1495
        if (!empty($setting)) {
1496
            header('X-Frame-Options: '.$setting);
1497
        }
1498
        // X-XSS-Protection
1499
        $setting = api_get_configuration_value('security_xss_protection');
1500
        if (!empty($setting)) {
1501
            header('X-XSS-Protection: '.$setting);
1502
        }
1503
        // X-Content-Type-Options
1504
        $setting = api_get_configuration_value('security_x_content_type_options');
1505
        if (!empty($setting)) {
1506
            header('X-Content-Type-Options: '.$setting);
1507
        }
1508
        // Referrer-Policy
1509
        $setting = api_get_configuration_value('security_referrer_policy');
1510
        if (!empty($setting)) {
1511
            header('Referrer-Policy: '.$setting);
1512
        }
1513
        // end of HTTP headers security block
1514
    }
1515
1516
    /**
1517
     * Assign favicon to the 'favico' template variable.
1518
     *
1519
     * @return bool Always return true because there is always at least one correct favicon.ico
1520
     */
1521
    private function assignFavIcon()
1522
    {
1523
        // Default root chamilo favicon
1524
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1525
1526
        //Added to verify if in the current Chamilo Theme exist a favicon
1527
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1528
1529
        //If exist pick the current chamilo theme favicon
1530
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1531
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1532
        }
1533
1534
        if (api_is_multiple_url_enabled()) {
1535
            /*$access_url_id = api_get_current_access_url_id();
1536
            if ($access_url_id != -1) {
1537
                $url_info = api_get_access_url($access_url_id);
1538
                $url = api_remove_trailing_slash(
1539
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1540
                );
1541
                $clean_url = api_replace_dangerous_char($url);
1542
                $clean_url = str_replace('/', '-', $clean_url);
1543
                $clean_url .= '/';
1544
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1545
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1546
                //we create the new dir for the new sites
1547
                if (is_file($icon_real_homep.'favicon.ico')) {
1548
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1549
                }
1550
            }*/
1551
        }
1552
1553
        $this->assign('favico', $favico);
1554
1555
        return true;
1556
    }
1557
1558
    /**
1559
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1560
     *
1561
     * @return bool Always return true (even if empty string)
1562
     */
1563
    private function assignAccessibilityBlock()
1564
    {
1565
        $resize = '';
1566
        if (api_get_setting('accessibility_font_resize') == 'true') {
1567
            $resize .= '<div class="resize_font">';
1568
            $resize .= '<div class="btn-group">';
1569
            $resize .= '<a title="'.get_lang('Decrease the font size').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1570
            $resize .= '<a title="'.get_lang('Reset the font size').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1571
            $resize .= '<a title="'.get_lang('Increase the font size').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1572
            $resize .= '</div>';
1573
            $resize .= '</div>';
1574
        }
1575
        $this->assign('accessibility', $resize);
1576
1577
        return true;
1578
    }
1579
1580
    /**
1581
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1582
     *
1583
     * @return bool Always return true (even if empty string)
1584
     */
1585
    private function assignSocialMeta()
0 ignored issues
show
Unused Code introduced by
The method assignSocialMeta() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1586
    {
1587
        $socialMeta = '';
1588
        $metaTitle = api_get_setting('meta_title');
1589
        if (!empty($metaTitle)) {
1590
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1591
            $metaSite = api_get_setting('meta_twitter_site');
1592
            if (!empty($metaSite)) {
1593
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1594
                $metaCreator = api_get_setting('meta_twitter_creator');
1595
                if (!empty($metaCreator)) {
1596
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1597
                }
1598
            }
1599
1600
            // The user badge page emits its own meta tags, so if this is
1601
            // enabled, ignore the global ones
1602
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1603
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1604
1605
            if (!$userId && !$skillId) {
1606
                // no combination of user and skill ID has been defined,
1607
                // so print the normal or course-specific OpenGraph meta tags
1608
                // Check for a course ID
1609
                $courseId = api_get_course_int_id();
1610
                // Check session ID from session/id/about (see .htaccess)
1611
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1612
1613
                if ($courseId != false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $courseId of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
1614
                    // If we are inside a course (even if within a session), publish info about the course
1615
                    $course = api_get_course_entity($courseId);
1616
                    // @TODO: support right-to-left in title
1617
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1618
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1619
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
1620
1621
                    $metaDescription = api_get_setting('meta_description');
1622
                    if (!empty($course->getDescription())) {
1623
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1624
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1625
                    } elseif (!empty($metaDescription)) {
1626
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1627
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1628
                    }
1629
1630
                    $picture = Container::getIllustrationRepository()->getIllustrationUrl($course);
1631
                    if (!empty($picture)) {
1632
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1633
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
1634
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1635
                    } else {
1636
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1637
                    }
1638
                } elseif ($sessionId !== 0) {
1639
                    // If we are on a session "about" screen, publish info about the session
1640
                    $em = Database::getManager();
1641
                    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
1642
1643
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1644
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1645
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."sessions/{$session->getId()}/about/".'" />'."\n";
1646
1647
                    $sessionValues = new ExtraFieldValue('session');
1648
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1649
                    $sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1650
1651
                    if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
1652
                        $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
1653
                        $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1654
                        $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
1655
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1656
                    } else {
1657
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1658
                    }
1659
                } else {
1660
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
1661
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1662
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
1663
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1664
1665
                    $metaDescription = api_get_setting('meta_description');
1666
                    if (!empty($metaDescription)) {
1667
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1668
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1669
                    }
1670
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1671
                }
1672
            }
1673
        }
1674
1675
        $this->assign('social_meta', $socialMeta);
1676
1677
        return true;
1678
    }
1679
1680
    /**
1681
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
1682
     *
1683
     * @param string $imageAlt The alt attribute for the image
1684
     *
1685
     * @return string The meta image HTML tag, or empty
1686
     */
1687
    private function getMetaPortalImagePath($imageAlt = '')
1688
    {
1689
        // Load portal meta image if defined
1690
        $metaImage = api_get_setting('meta_image_path');
1691
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
1692
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
1693
        $portalImageMeta = '';
1694
        if (!empty($metaImage)) {
1695
            if (is_file($metaImageSysPath)) {
1696
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
1697
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
1698
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1699
            }
1700
        } else {
1701
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
1702
            if (!empty($logo)) {
1703
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
1704
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
1705
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1706
            }
1707
        }
1708
1709
        return $portalImageMeta;
1710
    }
1711
}
1712