Completed
Push — master ( a08afa...b6711b )
by Julito
24:34
created

Template::setCssCustomFiles()   C

Complexity

Conditions 9
Paths 72

Size

Total Lines 59
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 27
nc 72
nop 0
dl 0
loc 59
rs 6.9133
c 0
b 0
f 0

How to fix   Long Method   

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
/**
5
 * Class Template
6
 *
7
 * @author Julio Montoya <[email protected]>
8
 * @todo better organization of the class, methods and variables
9
 *
10
 */
11
class Template
12
{
13
    /**
14
     * The Template folder name see main/template
15
     * @var string
16
     */
17
    public $templateFolder = 'default';
18
19
    /**
20
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
21
     * This variable is set from the database
22
     * @var string
23
     */
24
    public $theme = '';
25
    private $themeDir;
26
27
    /**
28
     * @var string
29
     */
30
    public $preview_theme = '';
31
    public $title = null;
32
    public $show_header;
33
    public $show_footer;
34
    public $help;
35
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
36
    public $show_learnpath = false; // This is a learnpath section or not?
37
    public $plugin = null;
38
    public $course_id = null;
39
    public $user_is_logged_in = false;
40
    public $twig = null;
41
42
    /* Loads chamilo plugins */
43
    public $load_plugins = false;
44
    public $params = [];
45
    public $force_plugin_load = false;
46
47
    /**
48
     * @param string $title
49
     * @param bool $show_header
50
     * @param bool $show_footer
51
     * @param bool $show_learnpath
52
     * @param bool $hide_global_chat
53
     * @param bool $load_plugins
54
     * @param bool $sendHeaders send http headers or not
55
     */
56
    public function __construct(
57
        $title = '',
58
        $show_header = true,
59
        $show_footer = true,
60
        $show_learnpath = false,
61
        $hide_global_chat = false,
62
        $load_plugins = true,
63
        $sendHeaders = true
64
    ) {
65
        // Page title
66
        $this->title = $title;
67
68
        $this->show_learnpath = $show_learnpath;
69
70
        if (empty($this->show_learnpath)) {
71
            $origin = api_get_origin();
72
            if ($origin === 'learnpath') {
73
                $this->show_learnpath = true;
74
                $show_footer = false;
75
                $show_header = false;
76
            }
77
        }
78
        $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...
79
        $this->load_plugins = $load_plugins;
80
81
        $template_paths = [
82
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
83
            api_get_path(SYS_CODE_PATH).'template', //template folder
84
            api_get_path(SYS_PLUGIN_PATH) // plugin folder
85
        ];
86
87
        $urlId = api_get_current_access_url_id();
88
89
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
90
91
        if (!is_dir($cache_folder)) {
92
            mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
93
        }
94
95
        $loader = new Twig_Loader_Filesystem($template_paths);
96
97
        $isTestMode = api_get_setting('server_type') === 'test';
98
99
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
100
        if ($isTestMode) {
101
            $options = [
102
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
103
                'autoescape' => false,
104
                'debug' => true,
105
                'auto_reload' => true,
106
                'optimizations' => 0,
107
                // turn on optimizations with -1
108
                'strict_variables' => false,
109
                //If set to false, Twig will silently ignore invalid variables
110
            ];
111
        } else {
112
            $options = [
113
                'cache' => $cache_folder,
114
                //path to the cache folder
115
                'autoescape' => false,
116
                'debug' => false,
117
                'auto_reload' => false,
118
                'optimizations' => -1,
119
                // turn on optimizations with -1
120
                'strict_variables' => false
121
                //If set to false, Twig will silently ignore invalid variables
122
            ];
123
        }
124
125
        $this->twig = new Twig_Environment($loader, $options);
126
127
        if ($isTestMode) {
128
            $this->twig->addExtension(new Twig_Extension_Debug());
129
        }
130
131
        // Twig filters setup
132
        $filters = [
133
            'get_plugin_lang',
134
            'get_lang',
135
            'api_get_path',
136
            'api_get_local_time',
137
            'api_convert_and_format_date',
138
            'api_is_allowed_to_edit',
139
            'api_get_user_info',
140
            'api_get_configuration_value',
141
            'api_get_setting',
142
            [
143
                'name' => 'return_message',
144
                'callable' => 'Display::return_message_and_translate'
145
            ],
146
            [
147
                'name' => 'display_page_header',
148
                'callable' => 'Display::page_header_and_translate'
149
            ],
150
            [
151
                'name' => 'display_page_subheader',
152
                'callable' => 'Display::page_subheader_and_translate'
153
            ],
154
            [
155
                'name' => 'icon',
156
                'callable' => 'Template::get_icon_path'
157
            ],
158
            [
159
                'name' => 'img',
160
                'callable' => 'Template::get_image'
161
            ],
162
            [
163
                'name' => 'format_date',
164
                'callable' => 'Template::format_date'
165
            ]
166
        ];
167
168
        foreach ($filters as $filter) {
169
            if (is_array($filter)) {
170
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
171
            } else {
172
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
173
            }
174
        }
175
176
        // Setting system variables
177
        $this->set_system_parameters();
178
179
        // Setting user variables
180
        $this->set_user_parameters();
181
182
        // Setting course variables
183
        $this->set_course_parameters();
184
185
        // Setting administrator variables
186
        $this->setAdministratorParams();
187
        //$this->setCSSEditor();
188
189
        // Header and footer are showed by default
190
        $this->set_footer($show_footer);
191
        $this->set_header($show_header);
192
193
        $this->set_header_parameters($sendHeaders);
194
        $this->set_footer_parameters();
195
196
        $defaultStyle = api_get_configuration_value('default_template');
197
        if (!empty($defaultStyle)) {
198
            $this->templateFolder = $defaultStyle;
199
        }
200
201
        $this->assign('template', $this->templateFolder);
202
        $this->assign('locale', api_get_language_isocode());
203
        $this->assign('login_class', null);
204
205
        $allow = api_get_configuration_value('show_language_selector_in_menu');
206
        if ($allow) {
207
            $this->assign('language_form', api_display_language_form());
208
        }
209
210
        // Chamilo plugins
211
        if ($this->show_header) {
212
            if ($this->load_plugins) {
213
                $this->plugin = new AppPlugin();
214
215
                //1. Showing installed plugins in regions
216
                $pluginRegions = $this->plugin->get_plugin_regions();
217
                foreach ($pluginRegions as $region) {
218
                    $this->set_plugin_region($region);
219
                }
220
221
                //2. Loading the course plugin info
222
                global $course_plugin;
223
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
224
                    //Load plugin get_langs
225
                    $this->plugin->load_plugin_lang_variables($course_plugin);
226
                }
227
            }
228
        }
229
    }
230
231
    /**
232
     * @param string $image
233
     * @param int $size
234
     *
235
     * @return string
236
     */
237
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
238
    {
239
        return Display::return_icon($image, '', [], $size, false, true);
240
    }
241
242
    /**
243
     * @param string $image
244
     * @param int $size
245
     * @param string $name
246
     * @return string
247
     */
248
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
249
    {
250
        return Display::return_icon($image, $name, [], $size);
251
    }
252
253
    /**
254
     * @param string $timestamp
255
     * @param string $format
256
     *
257
     * @return string
258
     */
259
    public static function format_date($timestamp, $format = null)
260
    {
261
        return api_format_date($timestamp, $format);
262
    }
263
264
    /**
265
     * Return the item's url key:
266
     *
267
     *      c_id=xx&id=xx
268
     *
269
     * @param object $item
270
     * @return string
271
     */
272
    public static function key($item)
273
    {
274
        $id     = isset($item->id) ? $item->id : null;
275
        $c_id   = isset($item->c_id) ? $item->c_id : null;
276
        $result = '';
277
        if ($c_id) {
278
            $result = "c_id=$c_id";
279
        }
280
        if ($id) {
281
            if ($result) {
282
                $result .= "&amp;id=$id";
283
            } else {
284
                $result .= "&amp;id=$id";
285
            }
286
        }
287
        return $result;
288
    }
289
290
    /**
291
     * @param string $helpInput
292
     */
293
    public function setHelp($helpInput = null)
294
    {
295
        if (!empty($helpInput)) {
296
            $help = $helpInput;
297
        } else {
298
            $help = $this->help;
299
        }
300
301
        $content = '';
302
        if (api_get_setting('enable_help_link') == 'true') {
303
            if (!empty($help)) {
304
                $help = Security::remove_XSS($help);
305
                $content = '<div class="help">';
306
                $content .= Display::url(
307
                    Display::return_icon('help.large.png', get_lang('Help')),
308
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
309
                    [
310
                        'class' => 'ajax',
311
                        'data-title' => get_lang('Help')
312
                    ]
313
                );
314
                $content .= '</div>';
315
            }
316
        }
317
        $this->assign('help_content', $content);
318
    }
319
320
    /**
321
     * Use template system to parse the actions menu
322
     * @todo finish it!
323
     **/
324
    public function set_actions($actions)
325
    {
326
        $action_string = '';
327
        if (!empty($actions)) {
328
            foreach ($actions as $action) {
329
                $action_string .= $action;
330
            }
331
        }
332
        $this->assign('actions', $actions);
333
    }
334
335
    /**
336
     * Shortcut to display a 1 col layout (index.php)
337
     * */
338
    public function display_one_col_template()
339
    {
340
        $tpl = $this->get_template('layout/layout_1_col.tpl');
341
        $this->display($tpl);
342
    }
343
344
    /**
345
     * Shortcut to display a 2 col layout (userportal.php)
346
     **/
347
    public function display_two_col_template()
348
    {
349
        $tpl = $this->get_template('layout/layout_2_col.tpl');
350
        $this->display($tpl);
351
    }
352
353
    /**
354
     * Displays an empty template
355
     */
356
    public function display_blank_template()
357
    {
358
        $tpl = $this->get_template('layout/blank.tpl');
359
        $this->display($tpl);
360
    }
361
362
    /**
363
     * Displays an empty template
364
     */
365
    public function displayBlankTemplateNoHeader()
366
    {
367
        $tpl = $this->get_template('layout/blank_no_header.tpl');
368
        $this->display($tpl);
369
    }
370
371
    /**
372
     * Displays an empty template
373
     */
374
    public function display_no_layout_template()
375
    {
376
        $tpl = $this->get_template('layout/no_layout.tpl');
377
        $this->display($tpl);
378
    }
379
380
    /**
381
     * Sets the footer visibility
382
     * @param bool true if we show the footer
383
     */
384
    public function set_footer($status)
385
    {
386
        $this->show_footer = $status;
387
        $this->assign('show_footer', $status);
388
    }
389
390
    /**
391
     * return true if toolbar has to be displayed for user
392
     * @return bool
393
     */
394
    public static function isToolBarDisplayedForUser()
395
    {
396
        //Toolbar
397
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
398
        $show_toolbar = false;
399
400
        switch ($show_admin_toolbar) {
401
            case 'do_not_show':
402
                break;
403
            case 'show_to_admin':
404
                if (api_is_platform_admin()) {
405
                    $show_toolbar = true;
406
                }
407
                break;
408
            case 'show_to_admin_and_teachers':
409
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
410
                    $show_toolbar = true;
411
                }
412
                break;
413
            case 'show_to_all':
414
                $show_toolbar = true;
415
                break;
416
        }
417
        return $show_toolbar;
418
    }
419
420
    /**
421
     * Sets the header visibility
422
     * @param bool true if we show the header
423
     */
424
    public function set_header($status)
425
    {
426
        $this->show_header = $status;
427
        $this->assign('show_header', $status);
428
429
        $show_toolbar = 0;
430
431
        if (self::isToolBarDisplayedForUser()) {
432
            $show_toolbar = 1;
433
        }
434
435
        $this->assign('show_toolbar', $show_toolbar);
436
437
        //Only if course is available
438
        $show_course_shortcut = null;
439
        $show_course_navigation_menu = null;
440
441
        if (!empty($this->course_id) && $this->user_is_logged_in) {
442
            if (api_get_setting('show_toolshortcuts') != 'false') {
443
                //Course toolbar
444
                $show_course_shortcut = CourseHome::show_navigation_tool_shortcuts();
445
            }
446
            if (api_get_setting('show_navigation_menu') != 'false') {
447
                //Course toolbar
448
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
449
            }
450
        }
451
        $this->assign('show_course_shortcut', $show_course_shortcut);
452
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
453
    }
454
455
    /**
456
     * Returns the sub-folder and filename for the given tpl file.
457
     * If template not found in overrides/ or custom template folder, the
458
     * default template will be used.
459
     * @param string $name
460
     *
461
     * @return string
462
     */
463
    public function get_template($name)
464
    {
465
        // Check if the tpl file is present in the main/template/overrides/ dir
466
        // Overrides is a special directory meant for temporary template
467
        // customization. It must be taken into account before anything else
468
        $file = api_get_path(SYS_CODE_PATH).'template/overrides/'.$name;
469
        if (is_readable($file)) {
470
            return 'overrides/'.$name;
471
        }
472
        // If a template folder has been manually defined, search for the right
473
        // file, and if not found, go for the same file in the default template
474
        if ($this->templateFolder != 'default') {
475
            // Avoid missing template error, use the default file.
476
            $file = api_get_path(SYS_CODE_PATH).'template/'.$this->templateFolder.'/'.$name;
477
            if (!file_exists($file)) {
478
                return 'default/'.$name;
479
            }
480
        }
481
482
        return $this->templateFolder.'/'.$name;
483
    }
484
485
    /**
486
     * Prepare the _c array for template files. The _c array contains
487
     * information about the current course
488
     * @return void
489
     */
490
    private function set_course_parameters()
491
    {
492
        //Setting course id
493
        $course = api_get_course_info();
494
        if (empty($course)) {
495
            $this->assign('course_is_set', false);
496
            return;
497
        }
498
        $this->assign('course_is_set', true);
499
        $this->course_id = $course['id'];
500
        $_c = [
501
            'id' => $course['real_id'],
502
            'code' => $course['code'],
503
            'title' => $course['name'],
504
            'visibility' => $course['visibility'],
505
            'language' => $course['language'],
506
            'directory' => $course['directory'],
507
            'session_id' => api_get_session_id(),
508
            'user_is_teacher' => api_is_course_admin(),
509
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
510
        ];
511
        $this->assign('course_code', $course['code']);
512
        $this->assign('_c', $_c);
513
    }
514
515
    /**
516
     * Prepare the _u array for template files. The _u array contains
517
     * information about the current user, as returned by
518
     * api_get_user_info()
519
     * @return void
520
     */
521
    private function set_user_parameters()
522
    {
523
        $user_info = [];
524
        $user_info['logged'] = 0;
525
        $this->user_is_logged_in = false;
526
        if (api_user_is_login()) {
527
            $user_info = api_get_user_info(api_get_user_id(), true);
528
            $user_info['logged'] = 1;
529
530
            $user_info['is_admin'] = 0;
531
            if (api_is_platform_admin()) {
532
                $user_info['is_admin'] = 1;
533
            }
534
535
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
536
            $this->user_is_logged_in = true;
537
        }
538
        // Setting the $_u array that could be use in any template
539
        $this->assign('_u', $user_info);
540
    }
541
542
    /**
543
     * Get CSS themes sub-directory
544
     * @param string $theme
545
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
546
     */
547
    public static function getThemeDir($theme)
548
    {
549
        $themeDir = 'themes/'.$theme.'/';
550
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
551
        if (!empty($virtualTheme)) {
552
            $virtualThemeList = api_get_themes(true);
553
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
554
            if ($isVirtualTheme) {
555
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
556
            }
557
        }
558
559
        return $themeDir;
560
    }
561
562
    /**
563
     * Get an array of all the web paths available (e.g. 'web' => 'https://my.chamilo.site/')
564
     * @return array
565
     */
566
    private function getWebPaths()
567
    {
568
        return [
569
            'web' => api_get_path(WEB_PATH),
570
            'web_url' => api_get_web_url(),
571
            'web_relative' => api_get_path(REL_PATH),
572
            'web_course' => api_get_path(WEB_COURSE_PATH),
573
            'web_main' => api_get_path(WEB_CODE_PATH),
574
            'web_css' => api_get_path(WEB_CSS_PATH),
575
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
576
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
577
            'web_img' => api_get_path(WEB_IMG_PATH),
578
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
579
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
580
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
581
            'web_self' => api_get_self(),
582
            'web_query_vars' => api_htmlentities($_SERVER['QUERY_STRING']),
583
            'web_self_query_vars' => api_htmlentities($_SERVER['REQUEST_URI']),
584
            'web_cid_query' => api_get_cidreq(),
585
        ];
586
    }
587
588
    /**
589
     * Set system parameters from api_get_configuration into _s array for use in TPLs
590
     * Also fills the _p array from getWebPaths()
591
     * @uses self::getWebPaths()
592
     */
593
    public function set_system_parameters()
594
    {
595
        $this->theme = api_get_visual_theme();
596
        if (!empty($this->preview_theme)) {
597
            $this->theme = $this->preview_theme;
598
        }
599
600
        $this->themeDir = self::getThemeDir($this->theme);
601
602
        // Setting app paths/URLs
603
        $this->assign('_p', $this->getWebPaths());
604
605
        // Here we can add system parameters that can be use in any template
606
        $_s = [
607
            'software_name' => api_get_configuration_value('software_name'),
608
            'system_version' => api_get_configuration_value('system_version'),
609
            'site_name' => api_get_setting('siteName'),
610
            'institution' => api_get_setting('Institution'),
611
            'date' => api_format_date('now', DATE_FORMAT_LONG),
612
            'timezone' => api_get_timezone(),
613
            'gamification_mode' => api_get_setting('gamification_mode')
614
        ];
615
        $this->assign('_s', $_s);
616
    }
617
618
    /**
619
     * Set legacy twig globals in order to be hook in the LegacyListener.php
620
     * @return array
621
     */
622
    public static function getGlobals()
623
    {
624
        $_p = [
625
            'web' => api_get_path(WEB_PATH),
626
            'web_relative' => api_get_path(REL_PATH),
627
            'web_course' => api_get_path(WEB_COURSE_PATH),
628
            'web_main' => api_get_path(WEB_CODE_PATH),
629
            'web_css' => api_get_path(WEB_CSS_PATH),
630
            //'web_css_theme' => api_get_path(WEB_CSS_PATH) . 'themes/' . $this->theme . '/',
631
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
632
            'web_img' => api_get_path(WEB_IMG_PATH),
633
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
634
            'web_plugin_asset' => api_get_path(WEB_PLUGIN_ASSET_PATH),
635
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
636
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
637
            'web_self' => api_get_self(),
638
            'web_query_vars' => api_htmlentities($_SERVER['QUERY_STRING']),
639
            'web_self_query_vars' => api_htmlentities($_SERVER['REQUEST_URI']),
640
            'web_cid_query' => api_get_cidreq(),
641
        ];
642
643
        $_s = [
644
            'software_name' => api_get_configuration_value('software_name'),
645
            'system_version' => api_get_configuration_value('system_version'),
646
            'site_name' => api_get_setting('siteName'),
647
            'institution' => api_get_setting('Institution'),
648
            'date' => api_format_date('now', DATE_FORMAT_LONG),
649
            'timezone' => api_get_timezone(),
650
            'gamification_mode' => api_get_setting('gamification_mode')
651
        ];
652
653
        //$user_info = api_get_user_info();
654
655
        return [
656
            '_p' => $_p,
657
            '_s' => $_s,
658
            //       '_u' => $user_info,
659
            'template' => 'default' // @todo setup template folder in config.yml;
660
        ];
661
    }
662
663
664
    /**
665
     * Set theme, include mainstream CSS files
666
     * @return void
667
     * @see setCssCustomFiles() for additional CSS sheets
668
     */
669
    public function setCssFiles()
670
    {
671
        global $disable_js_and_css_files;
672
        $css = [];
673
674
        // Default CSS Bootstrap
675
        $bowerCSSFiles = [
676
            'fontawesome/css/font-awesome.min.css',
677
            'jquery-ui/themes/smoothness/theme.css',
678
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
679
            'mediaelement/build/mediaelementplayer.min.css',
680
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
681
            'bootstrap/dist/css/bootstrap.min.css',
682
            'jquery.scrollbar/jquery.scrollbar.css',
683
            'bootstrap-daterangepicker/daterangepicker.css',
684
            'bootstrap-select/dist/css/bootstrap-select.min.css',
685
            'select2/dist/css/select2.min.css',
686
            'flag-icon-css/css/flag-icon.min.css'
687
        ];
688
689
        foreach ($bowerCSSFiles as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
690
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
691
        }
692
693
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
694
695
        if (api_is_global_chat_enabled()) {
696
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
697
        }
698
        $css_file_to_string = '';
699
        foreach ($css as $file) {
700
            $css_file_to_string .= api_get_css($file);
701
        }
702
703
        if (!$disable_js_and_css_files) {
704
            $this->assign('css_static_file_to_string', $css_file_to_string);
705
        }
706
    }
707
708
    /**
709
     *
710
     */
711
    public function setCSSEditor()
712
    {
713
        $cssEditor = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'editor.css');
714
        if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'editor.css')) {
715
            $cssEditor = api_get_path(WEB_CSS_PATH).$this->themeDir.'editor.css';
716
        }
717
718
        $this->assign('cssEditor', $cssEditor);
719
    }
720
721
    /**
722
     * Prepare custom CSS to be added at the very end of the <head> section
723
     * @return void
724
     * @see setCssFiles() for the mainstream CSS files
725
     */
726
    public function setCssCustomFiles()
727
    {
728
        global $disable_js_and_css_files;
729
        // chamilo CSS
730
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'../chamilo.css');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$css was never initialized. Although not strictly required by PHP, it is generally a good practice to add $css = array(); before regardless.
Loading history...
731
732
        // Base CSS
733
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.css');
734
735
        if ($this->show_learnpath) {
736
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
737
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
738
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
739
            }
740
        }
741
742
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
743
744
        $css_file_to_string = null;
745
        foreach ($css as $file) {
746
            $css_file_to_string .= api_get_css($file);
747
        }
748
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
749
        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...
750
            //hack in order to fix the actions buttons
751
            $css_file_to_string .= '<style>
752
                .td_actions a {
753
                    float:left;
754
                    width:100%;
755
                }
756
                .forum_message_left a {
757
                    float:left;
758
                    width:100%;
759
                }
760
                </style>';
761
        }
762
763
        $navigator_info = api_get_navigator();
764
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
765
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
766
        }
767
768
        if (!$disable_js_and_css_files) {
769
            $this->assign('css_custom_file_to_string', $css_file_to_string);
770
771
            $style_print = '';
772
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
773
                $style_print = api_get_css(
774
                    api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->theme.'/print.css'),
775
                    'print'
776
                );
777
            }
778
            $this->assign('css_style_print', $style_print);
779
        }
780
781
        // Logo
782
        $logo = return_logo($this->theme);
783
        $this->assign('logo', $logo);
784
        $this->assign('show_media_element', 1);
785
    }
786
787
    /**
788
     * Declare and define the template variable that will be used to load
789
     * javascript libraries in the header.
790
     */
791
    public function set_js_files()
792
    {
793
        global $disable_js_and_css_files, $htmlHeadXtra;
794
        $isoCode = api_get_language_isocode();
795
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
796
797
        if ($isoCode == 'en') {
798
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
799
        }
800
        // JS files
801
        $js_files = [
802
            'chosen/chosen.jquery.min.js'
803
        ];
804
805
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
806
807
        if (api_is_global_chat_enabled() || $viewBySession) {
808
            // Do not include the global chat in LP
809
            if ($this->show_learnpath == 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...
810
                $this->show_footer == 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...
811
                $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...
812
            ) {
813
                $js_files[] = 'chat/js/chat.js';
814
            }
815
        }
816
817
        if (api_get_setting('accessibility_font_resize') == 'true') {
818
            $js_files[] = 'fontresize.js';
819
        }
820
821
        $js_file_to_string = '';
822
        $bowerJsFiles = [
823
            'modernizr/modernizr.js',
824
            'jquery/dist/jquery.min.js',
825
            'bootstrap/dist/js/bootstrap.min.js',
826
            'jquery-ui/jquery-ui.min.js',
827
            'moment/min/moment-with-locales.js',
828
            'bootstrap-daterangepicker/daterangepicker.js',
829
            'jquery-timeago/jquery.timeago.js',
830
            'mediaelement/build/mediaelement-and-player.min.js',
831
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
832
            'image-map-resizer/js/imageMapResizer.min.js',
833
            'jquery.scrollbar/jquery.scrollbar.min.js',
834
            'readmore-js/readmore.min.js',
835
            'bootstrap-select/dist/js/bootstrap-select.min.js',
836
            $selectLink,
837
            'select2/dist/js/select2.min.js',
838
            "select2/dist/js/i18n/$isoCode.js"
839
        ];
840
        if (CHAMILO_LOAD_WYSIWYG == 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...
841
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
842
        }
843
844
        if (api_get_setting('include_asciimathml_script') == 'true') {
845
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
846
        }
847
848
        if ($isoCode != 'en') {
849
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
850
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
851
        }
852
853
        foreach ($bowerJsFiles as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
854
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
855
        }
856
857
        $js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/chamilo.js"></script>'."\n";
858
859
        foreach ($js_files as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
860
            //$js_file_to_string .= api_get_js($file);
861
        }
862
863
        // Loading email_editor js
864
        if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') {
865
            $template = $this->get_template('mail_editor/email_link.js.tpl');
866
            $js_file_to_string .= $this->fetch($template);
867
        }
868
869
        if (!$disable_js_and_css_files) {
870
            $this->assign('js_file_to_string', $js_file_to_string);
871
872
            $extra_headers = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
873
            //Adding jquery ui by default
874
            $extra_headers .= api_get_jquery_ui_js();
875
876
            //$extra_headers = '';
877
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
878
                foreach ($htmlHeadXtra as & $this_html_head) {
879
                    $extra_headers .= $this_html_head."\n";
880
                }
881
            }
882
            $this->assign('extra_headers', $extra_headers);
883
        }
884
    }
885
886
    /**
887
     * Special function to declare last-minute JS libraries which depend on
888
     * other things to be declared first. In particular, it might be useful
889
     * under IE9 with compatibility mode, which for some reason is getting
890
     * upset when a variable is used in a function (even if not used yet)
891
     * when this variable hasn't been defined yet.
892
     */
893
    public function set_js_files_post()
894
    {
895
        global $disable_js_and_css_files;
896
        $js_files = [];
897
        if (api_is_global_chat_enabled()) {
898
            //Do not include the global chat in LP
899
            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...
900
                $js_files[] = 'chat/js/chat.js';
901
            }
902
        }
903
        $js_file_to_string = null;
904
905
        foreach ($js_files as $js_file) {
906
            $js_file_to_string .= api_get_js($js_file);
907
        }
908
        if (!$disable_js_and_css_files) {
909
            $this->assign('js_file_to_string_post', $js_file_to_string);
910
        }
911
    }
912
913
    /**
914
     * Set header parameters
915
     * @param bool $sendHeaders send headers
916
     */
917
    private function set_header_parameters($sendHeaders)
918
    {
919
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
920
        $_course = api_get_course_info();
921
        $nameTools = $this->title;
922
        $navigation = return_navigation_array();
923
        $this->menu_navigation = $navigation['menu_navigation'];
924
925
        $this->assign('system_charset', api_get_system_encoding());
926
927
        if (isset($httpHeadXtra) && $httpHeadXtra) {
928
            foreach ($httpHeadXtra as & $thisHttpHead) {
929
                header($thisHttpHead);
930
            }
931
        }
932
933
        $this->assign(
934
            'online_button',
935
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
936
        );
937
        $this->assign(
938
            'offline_button',
939
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
940
        );
941
942
        // Get language iso-code for this page - ignore errors
943
        $this->assign('document_language', api_get_language_isocode());
944
945
        $course_title = isset($_course['name']) ? $_course['name'] : null;
946
947
        $title_list = [];
948
949
        $title_list[] = api_get_setting('Institution');
950
        $title_list[] = api_get_setting('siteName');
951
952
        if (!empty($course_title)) {
953
            $title_list[] = $course_title;
954
        }
955
        if ($nameTools != '') {
956
            $title_list[] = $nameTools;
957
        }
958
959
        $title_string = '';
960
        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...
961
            $title_string .= $title_list[$i];
962
            if (isset($title_list[$i + 1])) {
963
                $item = trim($title_list[$i + 1]);
964
                if (!empty($item)) {
965
                    $title_string .= ' - ';
966
                }
967
            }
968
        }
969
970
        $this->assign('title_string', $title_string);
971
972
        // Setting the theme and CSS files
973
        $this->setCssFiles();
974
        $this->set_js_files();
975
        $this->setCssCustomFiles();
976
977
        $browser = api_browser_support('check_browser');
978
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
979
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
980
            $this->assign('browser_specific_head', $browser_head);
981
        }
982
983
        // Implementation of prefetch.
984
        // See http://cdn.chamilo.org/main/img/online.png for details
985
        $prefetch = '';
986
        if (!empty($_configuration['cdn_enable'])) {
987
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
988
            foreach ($_configuration['cdn'] as $host => $exts) {
989
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
990
            }
991
        }
992
993
        $this->assign('prefetch', $prefetch);
994
        $this->assign('text_direction', api_get_text_direction());
995
        $this->assign('section_name', 'section-'.$this_section);
996
997
        // Default root chamilo favicon
998
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
999
1000
        //Added to verify if in the current Chamilo Theme exist a favicon
1001
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1002
1003
        //If exist pick the current chamilo theme favicon
1004
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1005
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1006
        }
1007
1008
        if (api_is_multiple_url_enabled()) {
1009
            $access_url_id = api_get_current_access_url_id();
1010
            if ($access_url_id != -1) {
1011
                $url_info = api_get_access_url($access_url_id);
1012
                $url = api_remove_trailing_slash(
1013
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1014
                );
1015
                $clean_url = api_replace_dangerous_char($url);
1016
                $clean_url = str_replace('/', '-', $clean_url);
1017
                $clean_url .= '/';
1018
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1019
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1020
                //we create the new dir for the new sites
1021
                if (is_file($icon_real_homep.'favicon.ico')) {
1022
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1023
                }
1024
            }
1025
        }
1026
1027
        $this->assign('favico', $favico);
1028
        $this->setHelp();
1029
1030
        //@todo move this in the template
1031
        $rightFloatMenu = '';
1032
        $iconBug = Display::return_icon(
1033
            'bug.png',
1034
            get_lang('ReportABug'),
1035
            [],
1036
            ICON_SIZE_LARGE
1037
        );
1038
        if (api_get_setting('show_link_bug_notification') == 'true' && $this->user_is_logged_in) {
1039
            $rightFloatMenu = '<div class="report">
1040
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1041
                    '.$iconBug.'
1042
                </a>
1043
		        </div>';
1044
        }
1045
1046
        if (api_get_setting('show_link_ticket_notification') == 'true' && $this->user_is_logged_in) {
1047
            // by default is project_id = 1
1048
            $iconTicket = Display::return_icon(
1049
                'bug.png',
1050
                get_lang('Ticket'),
1051
                [],
1052
                ICON_SIZE_LARGE
1053
            );
1054
            $courseInfo = api_get_course_info();
1055
            $courseParams = '';
1056
            if (!empty($courseInfo)) {
1057
                $courseParams = api_get_cidreq();
1058
            }
1059
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id=1&'.$courseParams;
1060
            $rightFloatMenu .= '<div class="report">
1061
		        <a href="'.$url.'" target="_blank">
1062
                    '.$iconTicket.'
1063
                </a>
1064
		    </div>';
1065
        }
1066
1067
        $this->assign('bug_notification', $rightFloatMenu);
1068
1069
        $resize = '';
1070
        if (api_get_setting('accessibility_font_resize') == 'true') {
1071
            $resize .= '<div class="resize_font">';
1072
            $resize .= '<div class="btn-group">';
1073
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1074
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1075
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1076
            $resize .= '</div>';
1077
            $resize .= '</div>';
1078
        }
1079
        $this->assign('accessibility', $resize);
1080
1081
        // Preparing values for the menu
1082
1083
        // Logout link
1084
        $hideLogout = api_get_setting('hide_logout_button');
1085
        if ($hideLogout === 'true') {
1086
            $this->assign('logout_link', null);
1087
        } else {
1088
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1089
        }
1090
1091
        // Profile link
1092
        if (api_get_setting('allow_social_tool') == 'true') {
1093
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1094
        } else {
1095
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1096
        }
1097
1098
        $this->assign('profile_url', $profile_url);
1099
1100
        //Message link
1101
        $message_link = null;
1102
        $message_url = null;
1103
        if (api_get_setting('allow_message_tool') == 'true') {
1104
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1105
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1106
        }
1107
        $this->assign('message_link', $message_link);
1108
        $this->assign('message_url', $message_url);
1109
1110
        // Certificate Link
1111
1112
        $allow = api_get_configuration_value('hide_my_certificate_link');
1113
        if ($allow === false) {
1114
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1115
            $certificateLink = Display::url(
1116
                get_lang('MyCertificates'),
1117
                $certificateUrl
1118
            );
1119
            $this->assign('certificate_link', $certificateLink);
1120
            $this->assign('certificate_url', $certificateUrl);
1121
        }
1122
1123
        $institution = api_get_setting('Institution');
1124
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1125
1126
        $this->assign('portal_name', $portal_name);
1127
1128
        //Menu
1129
        $menu = menuArray();
1130
        $this->assign('menu', $menu);
1131
1132
        $breadcrumb = '';
1133
        // Hide breadcrumb in LP
1134
        if ($this->show_learnpath == 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...
1135
            $breadcrumb = return_breadcrumb(
1136
                $interbreadcrumb,
1137
                $language_file,
1138
                $nameTools
1139
            );
1140
        }
1141
        $this->assign('breadcrumb', $breadcrumb);
1142
1143
        //Extra content
1144
        $extra_header = null;
1145
        if (!api_is_platform_admin()) {
1146
            $extra_header = trim(api_get_setting('header_extra_content'));
1147
        }
1148
        $this->assign('header_extra_content', $extra_header);
1149
1150
        if ($sendHeaders) {
1151
            header('Content-Type: text/html; charset='.api_get_system_encoding());
1152
            header(
1153
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1154
            );
1155
            self::addHTTPSecurityHeaders();
0 ignored issues
show
Bug Best Practice introduced by
The method Template::addHTTPSecurityHeaders() is not static, but was called statically. ( Ignorable by Annotation )

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

1155
            self::/** @scrutinizer ignore-call */ 
1156
                  addHTTPSecurityHeaders();
Loading history...
1156
        }
1157
1158
        $socialMeta = '';
1159
        $metaTitle = api_get_setting('meta_title');
1160
        if (!empty($metaTitle)) {
1161
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1162
            $metaSite = api_get_setting('meta_twitter_site');
1163
            if (!empty($metaSite)) {
1164
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1165
                $metaCreator = api_get_setting('meta_twitter_creator');
1166
                if (!empty($metaCreator)) {
1167
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1168
                }
1169
            }
1170
1171
            // The user badge page emits its own meta tags, so if this is
1172
            // enabled, ignore the global ones
1173
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1174
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1175
1176
            if (!$userId && !$skillId) {
1177
                // no combination of user and skill ID has been defined,
1178
                // so print the normal OpenGraph meta tags
1179
                $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1180
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1181
1182
                $metaDescription = api_get_setting('meta_description');
1183
                if (!empty($metaDescription)) {
1184
                    $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1185
                }
1186
1187
                $metaImage = api_get_setting('meta_image_path');
1188
                if (!empty($metaImage)) {
1189
                    if (is_file(api_get_path(SYS_PATH).$metaImage)) {
1190
                        $path = api_get_path(WEB_PATH).$metaImage;
1191
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1192
                    }
1193
                }
1194
            }
1195
        }
1196
1197
        $this->assign('social_meta', $socialMeta);
1198
    }
1199
1200
    /**
1201
     * Set footer parameters
1202
     */
1203
    private function set_footer_parameters()
1204
    {
1205
        if (api_get_setting('show_administrator_data') === 'true') {
1206
            $firstName = api_get_setting('administratorName');
1207
            $lastName = api_get_setting('administratorSurname');
1208
1209
            if (!empty($firstName) && !empty($lastName)) {
1210
                $name = api_get_person_name($firstName, $lastName);
1211
            } else {
1212
                $name = $lastName;
1213
                if (empty($lastName)) {
1214
                    $name = $firstName;
1215
                }
1216
            }
1217
1218
            $adminName = '';
1219
            // Administrator name
1220
            if (!empty($name)) {
1221
                $adminName = get_lang('Manager').' : '.
1222
                    Display::encrypted_mailto_link(
1223
                        api_get_setting('emailAdministrator'),
1224
                        $name
1225
                    );
1226
            }
1227
            $this->assign('administrator_name', $adminName);
1228
        }
1229
1230
        // Loading footer extra content
1231
        if (!api_is_platform_admin()) {
1232
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1233
            if (!empty($extra_footer)) {
1234
                $this->assign('footer_extra_content', $extra_footer);
1235
            }
1236
        }
1237
1238
        // Tutor name
1239
        if (api_get_setting('show_tutor_data') == 'true') {
1240
            // Course manager
1241
            $courseId = api_get_course_int_id();
1242
            $id_session = api_get_session_id();
1243
            if (!empty($courseId)) {
1244
                $tutor_data = '';
1245
                if ($id_session != 0) {
1246
                    $coachs_email = CourseManager::get_email_of_tutor_to_session(
1247
                        $id_session,
1248
                        $courseId
1249
                    );
1250
                    $email_link = [];
1251
                    foreach ($coachs_email as $coach) {
1252
                        $email_link[] = Display::encrypted_mailto_link($coach['email'], $coach['complete_name']);
1253
                    }
1254
                    if (count($coachs_email) > 1) {
1255
                        $tutor_data .= get_lang('Coachs').' : ';
1256
                        $tutor_data .= array_to_string($email_link, CourseManager::USER_SEPARATOR);
1257
                    } elseif (count($coachs_email) == 1) {
1258
                        $tutor_data .= get_lang('Coach').' : ';
1259
                        $tutor_data .= array_to_string($email_link, CourseManager::USER_SEPARATOR);
1260
                    } elseif (count($coachs_email) == 0) {
1261
                        $tutor_data .= '';
1262
                    }
1263
                }
1264
                $this->assign('session_teachers', $tutor_data);
1265
            }
1266
        }
1267
1268
        if (api_get_setting('show_teacher_data') == 'true') {
1269
            // course manager
1270
            $courseId = api_get_course_int_id();
1271
            if (!empty($courseId)) {
1272
                $teacher_data = '';
1273
                $mail = CourseManager::get_emails_of_tutors_to_course($courseId);
1274
                if (!empty($mail)) {
1275
                    $teachers_parsed = [];
1276
                    foreach ($mail as $value) {
1277
                        foreach ($value as $email => $name) {
1278
                            $teachers_parsed[] = Display::encrypted_mailto_link($email, $name);
1279
                        }
1280
                    }
1281
                    $label = get_lang('Teacher');
1282
                    if (count($mail) > 1) {
1283
                        $label = get_lang('Teachers');
1284
                    }
1285
                    $teacher_data .= $label.' : '.array_to_string($teachers_parsed, CourseManager::USER_SEPARATOR);
1286
                }
1287
                $this->assign('teachers', $teacher_data);
1288
            }
1289
        }
1290
    }
1291
1292
    /**
1293
     * Show header template.
1294
     */
1295
    public function show_header_template()
1296
    {
1297
        $tpl = $this->get_template('layout/show_header.tpl');
1298
        $this->display($tpl);
1299
    }
1300
1301
    /**
1302
     * Show footer template.
1303
     */
1304
    public function show_footer_template()
1305
    {
1306
        $tpl = $this->get_template('layout/show_footer.tpl');
1307
        $this->display($tpl);
1308
    }
1309
1310
    /**
1311
     * Show footer js template.
1312
     */
1313
    public function show_footer_js_template()
1314
    {
1315
        $tpl = $this->get_template('layout/footer.js.tpl');
1316
        $this->display($tpl);
1317
    }
1318
1319
    /**
1320
     * Sets the plugin content in a template variable
1321
     * @param string $pluginRegion
1322
     * @return null
1323
     */
1324
    public function set_plugin_region($pluginRegion)
1325
    {
1326
        if (!empty($pluginRegion)) {
1327
            $regionContent = $this->plugin->load_region(
1328
                $pluginRegion,
1329
                $this,
1330
                $this->force_plugin_load
1331
            );
1332
1333
            $pluginList = $this->plugin->get_installed_plugins();
1334
            foreach ($pluginList as $plugin_name) {
1335
                // The plugin_info variable is available inside the plugin index
1336
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
1337
1338
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
1339
                    $courseInfo = api_get_course_info();
1340
                    if (!empty($courseInfo)) {
1341
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
1342
                            /** @var Plugin $plugin */
1343
                            $plugin = $pluginInfo['obj'];
1344
                            $regionContent .= $plugin->renderRegion($pluginRegion);
1345
                        }
1346
                    }
1347
                } else {
1348
                    continue;
1349
                }
1350
            }
1351
1352
            if (!empty($regionContent)) {
1353
                $this->assign('plugin_'.$pluginRegion, $regionContent);
1354
            } else {
1355
                $this->assign('plugin_'.$pluginRegion, null);
1356
            }
1357
        }
1358
        return null;
1359
    }
1360
1361
    /**
1362
     * @param string $template
1363
     * @return string
1364
     */
1365
    public function fetch($template = null)
1366
    {
1367
        $template = $this->twig->loadTemplate($template);
1368
        return $template->render($this->params);
1369
    }
1370
1371
    /**
1372
     * @param string $variable
1373
     * @param mixed $value
1374
     */
1375
    public function assign($variable, $value = '')
1376
    {
1377
        $this->params[$variable] = $value;
1378
    }
1379
1380
    /**
1381
     * Render the template
1382
     * @param string $template The template path
1383
     * @param boolean $clearFlashMessages Clear the $_SESSION variables for flash messages
1384
     */
1385
    public function display($template, $clearFlashMessages = true)
1386
    {
1387
        $this->assign('flash_messages', Display::getFlashToString());
1388
1389
        if ($clearFlashMessages) {
1390
            Display::cleanFlashMessages();
1391
        }
1392
1393
        echo $this->twig->render($template, $this->params);
1394
    }
1395
1396
    /**
1397
     * Adds a body class for login pages
1398
     */
1399
    public function setLoginBodyClass()
1400
    {
1401
        $this->assign('login_class', 'section-login');
1402
    }
1403
1404
    /**
1405
     * The theme that will be used if the database is not working.
1406
     * @return string
1407
     */
1408
    public static function getThemeFallback()
1409
    {
1410
        $theme = api_get_configuration_value('theme_fallback');
1411
        if (empty($theme)) {
1412
            $theme = 'chamilo';
1413
        }
1414
        return $theme;
1415
    }
1416
1417
    /**
1418
     * @param bool|true $setLoginForm
1419
     */
1420
    public function setLoginForm($setLoginForm = true)
1421
    {
1422
        global $loginFailed;
1423
        $userId = api_get_user_id();
1424
        if (!($userId) || api_is_anonymous($userId)) {
1425
            // Only display if the user isn't logged in.
1426
            $this->assign(
1427
                'login_language_form',
1428
                api_display_language_form(true, true)
1429
            );
1430
            if ($setLoginForm) {
1431
                $this->assign('login_form', $this->displayLoginForm());
1432
1433
                if ($loginFailed) {
1434
                    $this->assign('login_failed', $this::handleLoginFailed());
0 ignored issues
show
Bug Best Practice introduced by
The method Template::handleLoginFailed() is not static, but was called statically. ( Ignorable by Annotation )

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

1434
                    $this->assign('login_failed', $this::/** @scrutinizer ignore-call */ handleLoginFailed());
Loading history...
1435
                }
1436
            }
1437
        }
1438
    }
1439
1440
    /**
1441
     * @return string
1442
     */
1443
    public function handleLoginFailed()
1444
    {
1445
        $message = get_lang('InvalidId');
1446
1447
        if (!isset($_GET['error'])) {
1448
            if (api_is_self_registration_allowed()) {
1449
                $message = get_lang('InvalidForSelfRegistration');
1450
            }
1451
        } else {
1452
            switch ($_GET['error']) {
1453
                case '':
1454
                    if (api_is_self_registration_allowed()) {
1455
                        $message = get_lang('InvalidForSelfRegistration');
1456
                    }
1457
                    break;
1458
                case 'account_expired':
1459
                    $message = get_lang('AccountExpired');
1460
                    break;
1461
                case 'account_inactive':
1462
                    $message = get_lang('AccountInactive');
1463
1464
                    if (api_get_setting('allow_registration') === 'confirmation') {
1465
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1466
                        $message .= Display::url(
1467
                            get_lang('ReSendConfirmationMail'),
1468
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php'
1469
                        );
1470
                    }
1471
                    break;
1472
                case 'user_password_incorrect':
1473
                    $message = get_lang('InvalidId');
1474
                    break;
1475
                case 'access_url_inactive':
1476
                    $message = get_lang('AccountURLInactive');
1477
                    break;
1478
                case 'wrong_captcha':
1479
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1480
                    break;
1481
                case 'blocked_by_captcha':
1482
                    $message = get_lang('AccountBlockedByCaptcha');
1483
                    break;
1484
                case 'multiple_connection_not_allowed':
1485
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1486
                    break;
1487
                case 'unrecognize_sso_origin':
1488
                    //$message = get_lang('SSOError');
1489
                    break;
1490
            }
1491
        }
1492
        return Display::return_message($message, 'error', false);
1493
    }
1494
1495
    /**
1496
     * @return string
1497
     */
1498
    public function displayLoginForm()
1499
    {
1500
        $form = new FormValidator(
1501
            'formLogin',
1502
            'POST',
1503
            null,
1504
            null,
1505
            null,
1506
            FormValidator::LAYOUT_BOX_NO_LABEL
1507
        );
1508
        $params = [
1509
            'id' => 'login',
1510
            'autofocus' => 'autofocus',
1511
            'icon' => 'user fa-fw',
1512
            'placeholder' => get_lang('UserName'),
1513
        ];
1514
        $browserAutoCapitalize= false;
1515
        // Avoid showing the autocapitalize option if the browser doesn't
1516
        // support it: this attribute is against the HTML5 standard
1517
        if (api_browser_support('autocapitalize')) {
1518
            $browserAutoCapitalize = false;
1519
            $params['autocapitalize'] = 'none';
1520
        }
1521
        $form->addText(
1522
            'login',
1523
            get_lang('UserName'),
1524
            true,
1525
            $params
1526
        );
1527
        $params = [
1528
            'id' => 'password',
1529
            'icon' => 'lock fa-fw',
1530
            'placeholder' => get_lang('Pass'),
1531
        ];
1532
        if ($browserAutoCapitalize) {
1533
            $params['autocapitalize'] = 'none';
1534
        }
1535
        $form->addElement(
1536
            'password',
1537
            'password',
1538
            get_lang('Pass'),
1539
            $params
1540
        );
1541
        // Captcha
1542
        $captcha = api_get_setting('allow_captcha');
1543
        $allowCaptcha = $captcha === 'true';
1544
1545
        if ($allowCaptcha) {
1546
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1547
            if ($useCaptcha) {
1548
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1549
                $options = [
1550
                    'width' => 250,
1551
                    'height' => 90,
1552
                    'callback'     => $ajax.'&var='.basename(__FILE__, '.php'),
1553
                    'sessionVar'   => basename(__FILE__, '.php'),
1554
                    'imageOptions' => [
1555
                        'font_size' => 20,
1556
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1557
                        'font_file' => 'OpenSans-Regular.ttf',
1558
                        //'output' => 'gif'
1559
                    ]
1560
                ];
1561
1562
                // Minimum options using all defaults (including defaults for Image_Text):
1563
                //$options = array('callback' => 'qfcaptcha_image.php');
1564
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1565
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1566
1567
                $form->addElement(
1568
                    'text',
1569
                    'captcha',
1570
                    get_lang('EnterTheLettersYouSee')
1571
                );
1572
                $form->addRule(
1573
                    'captcha',
1574
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1575
                    'required',
1576
                    null,
1577
                    'client'
1578
                );
1579
                $form->addRule(
1580
                    'captcha',
1581
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1582
                    'CAPTCHA',
1583
                    $captcha_question
1584
                );
1585
            }
1586
        }
1587
1588
        $form->addButton(
1589
            'submitAuth',
1590
            get_lang('LoginEnter'),
1591
            null,
1592
            'primary',
1593
            null,
1594
            'btn-block'
1595
        );
1596
1597
        $html = $form->returnForm();
1598
        if (api_get_setting('openid_authentication') == 'true') {
1599
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1600
            $html .= '<div>'.openid_form().'</div>';
0 ignored issues
show
Bug introduced by
The function openid_form was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1600
            $html .= '<div>'./** @scrutinizer ignore-call */ openid_form().'</div>';
Loading history...
1601
        }
1602
1603
        return $html;
1604
    }
1605
1606
    /**
1607
     * Set administrator variables
1608
     */
1609
    private function setAdministratorParams()
1610
    {
1611
        $_admin = [
1612
            'email' => api_get_setting('emailAdministrator'),
1613
            'surname' => api_get_setting('administratorSurname'),
1614
            'name' => api_get_setting('administratorName'),
1615
            'telephone' => api_get_setting('administratorTelephone')
1616
        ];
1617
1618
        $this->assign('_admin', $_admin);
1619
    }
1620
1621
    /**
1622
     * Manage specific HTTP headers security
1623
     * @return void (prints headers directly)
1624
     */
1625
    private function addHTTPSecurityHeaders()
1626
    {
1627
        // Implementation of HTTP headers security, as suggested and checked
1628
        // by https://securityheaders.io/
1629
        // Enable these settings in configuration.php to use them on your site
1630
        // Strict-Transport-Security
1631
        $setting = api_get_configuration_value('security_strict_transport');
1632
        if (!empty($setting)) {
1633
            header('Strict-Transport-Security: '.$setting);
1634
        }
1635
        // Content-Security-Policy
1636
        $setting = api_get_configuration_value('security_content_policy');
1637
        if (!empty($setting)) {
1638
            header('Content-Security-Policy: '.$setting);
1639
        }
1640
        $setting = api_get_configuration_value('security_content_policy_report_only');
1641
        if (!empty($setting)) {
1642
            header('Content-Security-Policy-Report-Only: '.$setting);
1643
        }
1644
        // Public-Key-Pins
1645
        $setting = api_get_configuration_value('security_public_key_pins');
1646
        if (!empty($setting)) {
1647
            header('Public-Key-Pins: '.$setting);
1648
        }
1649
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1650
        if (!empty($setting)) {
1651
            header('Public-Key-Pins-Report-Only: '.$setting);
1652
        }
1653
        // X-Frame-Options
1654
        $setting = api_get_configuration_value('security_x_frame_options');
1655
        if (!empty($setting)) {
1656
            header('X-Frame-Options: '.$setting);
1657
        }
1658
        // X-XSS-Protection
1659
        $setting = api_get_configuration_value('security_xss_protection');
1660
        if (!empty($setting)) {
1661
            header('X-XSS-Protection: '.$setting);
1662
        }
1663
        // X-Content-Type-Options
1664
        $setting = api_get_configuration_value('security_x_content_type_options');
1665
        if (!empty($setting)) {
1666
            header('X-Content-Type-Options: '.$setting);
1667
        }
1668
        // Referrer-Policy
1669
        $setting = api_get_configuration_value('security_referrer_policy');
1670
        if (!empty($setting)) {
1671
            header('Referrer-Policy: '.$setting);
1672
        }
1673
        // end of HTTP headers security block
1674
    }
1675
}
1676