Completed
Push — master ( bdb7fb...d3d147 )
by Julito
25:16
created

Template::returnTeachersNames()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 0
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
5
use Chamilo\UserBundle\Entity\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, User. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
7
/**
8
 * Class Template
9
 *
10
 * @author Julio Montoya <[email protected]>
11
 * @todo better organization of the class, methods and variables
12
 *
13
 */
14
class Template
15
{
16
    /**
17
     * The Template folder name see main/template
18
     * @var string
19
     */
20
    public $templateFolder = 'default';
21
22
    /**
23
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
24
     * This variable is set from the database
25
     * @var string
26
     */
27
    public $theme = '';
28
    private $themeDir;
29
30
    /**
31
     * @var string
32
     */
33
    public $preview_theme = '';
34
    public $title = null;
35
    public $show_header;
36
    public $show_footer;
37
    public $help;
38
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
39
    public $show_learnpath = false; // This is a learnpath section or not?
40
    public $plugin = null;
41
    public $course_id = null;
42
    public $user_is_logged_in = false;
43
    public $twig = null;
44
45
    /* Loads chamilo plugins */
46
    public $load_plugins = false;
47
    public $params = [];
48
    public $force_plugin_load = false;
49
    public $responseCode = 0;
50
51
    /**
52
     * @param string $title
53
     * @param bool $show_header
54
     * @param bool $show_footer
55
     * @param bool $show_learnpath
56
     * @param bool $hide_global_chat
57
     * @param bool $load_plugins
58
     * @param int $responseCode
59
     * @param bool $sendHeaders send http headers or not
60
     */
61
    public function __construct(
62
        $title = '',
63
        $show_header = true,
64
        $show_footer = true,
65
        $show_learnpath = false,
66
        $hide_global_chat = false,
67
        $load_plugins = true,
68
        $sendHeaders = true,
69
        $responseCode = 0
70
    ) {
71
        // Page title
72
        $this->title = $title;
73
        $this->show_learnpath = $show_learnpath;
74
        $this->setResponseCode($responseCode);
75
76
        if (empty($this->show_learnpath)) {
77
            $origin = api_get_origin();
78
            if ($origin === 'learnpath') {
79
                $this->show_learnpath = true;
80
                $show_footer = false;
81
                $show_header = false;
82
            }
83
        }
84
        $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...
85
        $this->load_plugins = $load_plugins;
86
87
        $template_paths = [
88
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
89
            api_get_path(SYS_CODE_PATH).'template', //template folder
90
            api_get_path(SYS_PLUGIN_PATH) // plugin folder
91
        ];
92
93
        $urlId = api_get_current_access_url_id();
94
95
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
96
97
        if (!is_dir($cache_folder)) {
98
            mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
99
        }
100
101
        $loader = new Twig_Loader_Filesystem($template_paths);
102
103
        $isTestMode = api_get_setting('server_type') === 'test';
104
105
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
106
        if ($isTestMode) {
107
            $options = [
108
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
109
                'autoescape' => false,
110
                'debug' => true,
111
                'auto_reload' => true,
112
                'optimizations' => 0,
113
                // turn on optimizations with -1
114
                'strict_variables' => false,
115
                //If set to false, Twig will silently ignore invalid variables
116
            ];
117
        } else {
118
            $options = [
119
                'cache' => $cache_folder,
120
                //path to the cache folder
121
                'autoescape' => false,
122
                'debug' => false,
123
                'auto_reload' => false,
124
                'optimizations' => -1,
125
                // turn on optimizations with -1
126
                'strict_variables' => false
127
                //If set to false, Twig will silently ignore invalid variables
128
            ];
129
        }
130
131
        $this->twig = new Twig_Environment($loader, $options);
132
133
        if ($isTestMode) {
134
            $this->twig->addExtension(new Twig_Extension_Debug());
135
        }
136
137
        // Twig filters setup
138
        $filters = [
139
            'get_plugin_lang',
140
            'get_lang',
141
            'api_get_path',
142
            'api_get_local_time',
143
            'api_convert_and_format_date',
144
            'api_is_allowed_to_edit',
145
            'api_get_user_info',
146
            'api_get_configuration_value',
147
            'api_get_setting',
148
            [
149
                'name' => 'return_message',
150
                'callable' => 'Display::return_message_and_translate'
151
            ],
152
            [
153
                'name' => 'display_page_header',
154
                'callable' => 'Display::page_header_and_translate'
155
            ],
156
            [
157
                'name' => 'display_page_subheader',
158
                'callable' => 'Display::page_subheader_and_translate'
159
            ],
160
            [
161
                'name' => 'icon',
162
                'callable' => 'Template::get_icon_path'
163
            ],
164
            [
165
                'name' => 'img',
166
                'callable' => 'Template::get_image'
167
            ],
168
            [
169
                'name' => 'format_date',
170
                'callable' => 'Template::format_date'
171
            ]
172
        ];
173
174
        foreach ($filters as $filter) {
175
            if (is_array($filter)) {
176
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
177
            } else {
178
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
179
            }
180
        }
181
182
        $functions = [
183
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
184
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames']
185
        ];
186
187
        foreach ($functions as $function) {
188
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
189
        }
190
191
        // Setting system variables
192
        $this->set_system_parameters();
193
194
        // Setting user variables
195
        $this->set_user_parameters();
196
197
        // Setting course variables
198
        $this->set_course_parameters();
199
200
        // Setting administrator variables
201
        $this->setAdministratorParams();
202
        //$this->setCSSEditor();
203
204
        // Header and footer are showed by default
205
        $this->set_footer($show_footer);
206
        $this->set_header($show_header);
207
208
        $this->set_header_parameters($sendHeaders);
209
        $this->set_footer_parameters();
210
211
        $defaultStyle = api_get_configuration_value('default_template');
212
        if (!empty($defaultStyle)) {
213
            $this->templateFolder = $defaultStyle;
214
        }
215
216
        $this->assign('template', $this->templateFolder);
217
        $this->assign('locale', api_get_language_isocode());
218
        $this->assign('login_class', null);
219
220
        $allow = api_get_configuration_value('show_language_selector_in_menu');
221
        if ($allow) {
222
            $this->assign('language_form', api_display_language_form());
223
        }
224
225
        // Chamilo plugins
226
        if ($this->show_header) {
227
            if ($this->load_plugins) {
228
                $this->plugin = new AppPlugin();
229
230
                //1. Showing installed plugins in regions
231
                $pluginRegions = $this->plugin->get_plugin_regions();
232
                foreach ($pluginRegions as $region) {
233
                    $this->set_plugin_region($region);
234
                }
235
236
                //2. Loading the course plugin info
237
                global $course_plugin;
238
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
239
                    //Load plugin get_langs
240
                    $this->plugin->load_plugin_lang_variables($course_plugin);
241
                }
242
            }
243
        }
244
    }
245
246
    /**
247
     * @param string $image
248
     * @param int $size
249
     *
250
     * @return string
251
     */
252
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
253
    {
254
        return Display::return_icon($image, '', [], $size, false, true);
255
    }
256
257
    /**
258
     * @param string $image
259
     * @param int $size
260
     * @param string $name
261
     * @return string
262
     */
263
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
264
    {
265
        return Display::return_icon($image, $name, [], $size);
266
    }
267
268
    /**
269
     * @param string $timestamp
270
     * @param string $format
271
     *
272
     * @return string
273
     */
274
    public static function format_date($timestamp, $format = null)
275
    {
276
        return api_format_date($timestamp, $format);
277
    }
278
279
    /**
280
     * Return the item's url key:
281
     *
282
     *      c_id=xx&id=xx
283
     *
284
     * @param object $item
285
     * @return string
286
     */
287
    public static function key($item)
288
    {
289
        $id     = isset($item->id) ? $item->id : null;
290
        $c_id   = isset($item->c_id) ? $item->c_id : null;
291
        $result = '';
292
        if ($c_id) {
293
            $result = "c_id=$c_id";
294
        }
295
        if ($id) {
296
            if ($result) {
297
                $result .= "&amp;id=$id";
298
            } else {
299
                $result .= "&amp;id=$id";
300
            }
301
        }
302
        return $result;
303
    }
304
305
    /**
306
     * @param string $helpInput
307
     */
308
    public function setHelp($helpInput = null)
309
    {
310
        if (!empty($helpInput)) {
311
            $help = $helpInput;
312
        } else {
313
            $help = $this->help;
314
        }
315
316
        $content = '';
317
        if (api_get_setting('enable_help_link') == 'true') {
318
            if (!empty($help)) {
319
                $help = Security::remove_XSS($help);
320
                $content = '<div class="help">';
321
                $content .= Display::url(
322
                    Display::return_icon('help.large.png', get_lang('Help')),
323
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
324
                    [
325
                        'class' => 'ajax',
326
                        'data-title' => get_lang('Help')
327
                    ]
328
                );
329
                $content .= '</div>';
330
            }
331
        }
332
        $this->assign('help_content', $content);
333
    }
334
335
    /**
336
     * Use template system to parse the actions menu
337
     * @todo finish it!
338
     **/
339
    public function set_actions($actions)
340
    {
341
        $action_string = '';
342
        if (!empty($actions)) {
343
            foreach ($actions as $action) {
344
                $action_string .= $action;
345
            }
346
        }
347
        $this->assign('actions', $actions);
348
    }
349
350
    /**
351
     * Shortcut to display a 1 col layout (index.php)
352
     * */
353
    public function display_one_col_template()
354
    {
355
        $tpl = $this->get_template('layout/layout_1_col.tpl');
356
        $this->display($tpl);
357
    }
358
359
    /**
360
     * Shortcut to display a 2 col layout (userportal.php)
361
     **/
362
    public function display_two_col_template()
363
    {
364
        $tpl = $this->get_template('layout/layout_2_col.tpl');
365
        $this->display($tpl);
366
    }
367
368
    /**
369
     * Displays an empty template
370
     */
371
    public function display_blank_template()
372
    {
373
        $tpl = $this->get_template('layout/blank.tpl');
374
        $this->display($tpl);
375
    }
376
377
    /**
378
     * Displays an empty template
379
     */
380
    public function displayBlankTemplateNoHeader()
381
    {
382
        $tpl = $this->get_template('layout/blank_no_header.tpl');
383
        $this->display($tpl);
384
    }
385
386
    /**
387
     * Displays an empty template
388
     */
389
    public function display_no_layout_template()
390
    {
391
        $tpl = $this->get_template('layout/no_layout.tpl');
392
        $this->display($tpl);
393
    }
394
395
    /**
396
     * Sets the footer visibility
397
     * @param bool true if we show the footer
398
     */
399
    public function set_footer($status)
400
    {
401
        $this->show_footer = $status;
402
        $this->assign('show_footer', $status);
403
    }
404
405
    /**
406
     * return true if toolbar has to be displayed for user
407
     * @return bool
408
     */
409
    public static function isToolBarDisplayedForUser()
410
    {
411
        //Toolbar
412
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
413
        $show_toolbar = false;
414
415
        switch ($show_admin_toolbar) {
416
            case 'do_not_show':
417
                break;
418
            case 'show_to_admin':
419
                if (api_is_platform_admin()) {
420
                    $show_toolbar = true;
421
                }
422
                break;
423
            case 'show_to_admin_and_teachers':
424
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
425
                    $show_toolbar = true;
426
                }
427
                break;
428
            case 'show_to_all':
429
                $show_toolbar = true;
430
                break;
431
        }
432
        return $show_toolbar;
433
    }
434
435
    /**
436
     * Sets the header visibility
437
     * @param bool true if we show the header
438
     */
439
    public function set_header($status)
440
    {
441
        $this->show_header = $status;
442
        $this->assign('show_header', $status);
443
444
        $show_toolbar = 0;
445
446
        if (self::isToolBarDisplayedForUser()) {
447
            $show_toolbar = 1;
448
        }
449
450
        $this->assign('show_toolbar', $show_toolbar);
451
452
        //Only if course is available
453
        $show_course_shortcut = null;
454
        $show_course_navigation_menu = null;
455
456
        if (!empty($this->course_id) && $this->user_is_logged_in) {
457
            if (api_get_setting('show_toolshortcuts') != 'false') {
458
                //Course toolbar
459
                $show_course_shortcut = CourseHome::show_navigation_tool_shortcuts();
460
            }
461
            if (api_get_setting('show_navigation_menu') != 'false') {
462
                //Course toolbar
463
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
464
            }
465
        }
466
        $this->assign('show_course_shortcut', $show_course_shortcut);
467
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
468
    }
469
470
    /**
471
     * Returns the sub-folder and filename for the given tpl file.
472
     * If template not found in overrides/ or custom template folder, the
473
     * default template will be used.
474
     * @param string $name
475
     *
476
     * @return string
477
     */
478
    public function get_template($name)
479
    {
480
        // Check if the tpl file is present in the main/template/overrides/ dir
481
        // Overrides is a special directory meant for temporary template
482
        // customization. It must be taken into account before anything else
483
        $file = api_get_path(SYS_CODE_PATH).'template/overrides/'.$name;
484
        if (is_readable($file)) {
485
            return 'overrides/'.$name;
486
        }
487
        // If a template folder has been manually defined, search for the right
488
        // file, and if not found, go for the same file in the default template
489
        if ($this->templateFolder != 'default') {
490
            // Avoid missing template error, use the default file.
491
            $file = api_get_path(SYS_CODE_PATH).'template/'.$this->templateFolder.'/'.$name;
492
            if (!file_exists($file)) {
493
                return 'default/'.$name;
494
            }
495
        }
496
497
        return $this->templateFolder.'/'.$name;
498
    }
499
500
    /**
501
     * Prepare the _c array for template files. The _c array contains
502
     * information about the current course
503
     * @return void
504
     */
505
    private function set_course_parameters()
506
    {
507
        //Setting course id
508
        $course = api_get_course_info();
509
        if (empty($course)) {
510
            $this->assign('course_is_set', false);
511
            return;
512
        }
513
        $this->assign('course_is_set', true);
514
        $this->course_id = $course['id'];
515
        $_c = [
516
            'id' => $course['real_id'],
517
            'code' => $course['code'],
518
            'title' => $course['name'],
519
            'visibility' => $course['visibility'],
520
            'language' => $course['language'],
521
            'directory' => $course['directory'],
522
            'session_id' => api_get_session_id(),
523
            'user_is_teacher' => api_is_course_admin(),
524
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
525
        ];
526
        $this->assign('course_code', $course['code']);
527
        $this->assign('_c', $_c);
528
    }
529
530
    /**
531
     * Prepare the _u array for template files. The _u array contains
532
     * information about the current user, as returned by
533
     * api_get_user_info()
534
     * @return void
535
     */
536
    private function set_user_parameters()
537
    {
538
        $user_info = [];
539
        $user_info['logged'] = 0;
540
        $this->user_is_logged_in = false;
541
        if (api_user_is_login()) {
542
            $user_info = api_get_user_info(api_get_user_id(), true);
543
            $user_info['logged'] = 1;
544
545
            $user_info['is_admin'] = 0;
546
            if (api_is_platform_admin()) {
547
                $user_info['is_admin'] = 1;
548
            }
549
550
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
551
            $this->user_is_logged_in = true;
552
        }
553
        // Setting the $_u array that could be use in any template
554
        $this->assign('_u', $user_info);
555
    }
556
557
    /**
558
     * Get CSS themes sub-directory
559
     * @param string $theme
560
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
561
     */
562
    public static function getThemeDir($theme)
563
    {
564
        $themeDir = 'themes/'.$theme.'/';
565
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
566
        if (!empty($virtualTheme)) {
567
            $virtualThemeList = api_get_themes(true);
568
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
569
            if ($isVirtualTheme) {
570
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
571
            }
572
        }
573
574
        return $themeDir;
575
    }
576
577
    /**
578
     * Get an array of all the web paths available (e.g. 'web' => 'https://my.chamilo.site/')
579
     * @return array
580
     */
581
    private function getWebPaths()
582
    {
583
        return [
584
            'web' => api_get_path(WEB_PATH),
585
            'web_url' => api_get_web_url(),
586
            'web_relative' => api_get_path(REL_PATH),
587
            'web_course' => api_get_path(WEB_COURSE_PATH),
588
            'web_main' => api_get_path(WEB_CODE_PATH),
589
            'web_css' => api_get_path(WEB_CSS_PATH),
590
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
591
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
592
            'web_img' => api_get_path(WEB_IMG_PATH),
593
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
594
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
595
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
596
            'web_self' => api_get_self(),
597
            'web_query_vars' => api_htmlentities($_SERVER['QUERY_STRING']),
598
            'web_self_query_vars' => api_htmlentities($_SERVER['REQUEST_URI']),
599
            'web_cid_query' => api_get_cidreq(),
600
        ];
601
    }
602
603
    /**
604
     * Set system parameters from api_get_configuration into _s array for use in TPLs
605
     * Also fills the _p array from getWebPaths()
606
     * @uses self::getWebPaths()
607
     */
608
    public function set_system_parameters()
609
    {
610
        $this->theme = api_get_visual_theme();
611
        if (!empty($this->preview_theme)) {
612
            $this->theme = $this->preview_theme;
613
        }
614
615
        $this->themeDir = self::getThemeDir($this->theme);
616
617
        // Setting app paths/URLs
618
        $this->assign('_p', $this->getWebPaths());
619
620
        // Here we can add system parameters that can be use in any template
621
        $_s = [
622
            'software_name' => api_get_configuration_value('software_name'),
623
            'system_version' => api_get_configuration_value('system_version'),
624
            'site_name' => api_get_setting('siteName'),
625
            'institution' => api_get_setting('Institution'),
626
            'date' => api_format_date('now', DATE_FORMAT_LONG),
627
            'timezone' => api_get_timezone(),
628
            'gamification_mode' => api_get_setting('gamification_mode')
629
        ];
630
        $this->assign('_s', $_s);
631
    }
632
633
    /**
634
     * Set legacy twig globals in order to be hook in the LegacyListener.php
635
     * @return array
636
     */
637
    public static function getGlobals()
638
    {
639
        $_p = [
640
            'web' => api_get_path(WEB_PATH),
641
            'web_relative' => api_get_path(REL_PATH),
642
            'web_course' => api_get_path(WEB_COURSE_PATH),
643
            'web_main' => api_get_path(WEB_CODE_PATH),
644
            'web_css' => api_get_path(WEB_CSS_PATH),
645
            //'web_css_theme' => api_get_path(WEB_CSS_PATH) . 'themes/' . $this->theme . '/',
646
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
647
            'web_img' => api_get_path(WEB_IMG_PATH),
648
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
649
            'web_plugin_asset' => api_get_path(WEB_PLUGIN_ASSET_PATH),
650
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
651
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
652
            'web_self' => api_get_self(),
653
            'web_query_vars' => api_htmlentities($_SERVER['QUERY_STRING']),
654
            'web_self_query_vars' => api_htmlentities($_SERVER['REQUEST_URI']),
655
            'web_cid_query' => api_get_cidreq(),
656
        ];
657
658
        $_s = [
659
            'software_name' => api_get_configuration_value('software_name'),
660
            'system_version' => api_get_configuration_value('system_version'),
661
            'site_name' => api_get_setting('siteName'),
662
            'institution' => api_get_setting('Institution'),
663
            'date' => api_format_date('now', DATE_FORMAT_LONG),
664
            'timezone' => api_get_timezone(),
665
            'gamification_mode' => api_get_setting('gamification_mode')
666
        ];
667
668
        //$user_info = api_get_user_info();
669
670
        return [
671
            '_p' => $_p,
672
            '_s' => $_s,
673
            //       '_u' => $user_info,
674
            'template' => 'default' // @todo setup template folder in config.yml;
675
        ];
676
    }
677
678
679
    /**
680
     * Set theme, include mainstream CSS files
681
     * @return void
682
     * @see setCssCustomFiles() for additional CSS sheets
683
     */
684
    public function setCssFiles()
685
    {
686
        global $disable_js_and_css_files;
687
        $css = [];
688
689
        // Default CSS Bootstrap
690
        $bowerCSSFiles = [
691
            'fontawesome/css/font-awesome.min.css',
692
            'jquery-ui/themes/smoothness/theme.css',
693
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
694
            'mediaelement/build/mediaelementplayer.min.css',
695
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
696
            'bootstrap/dist/css/bootstrap.min.css',
697
            'jquery.scrollbar/jquery.scrollbar.css',
698
            'bootstrap-daterangepicker/daterangepicker.css',
699
            'bootstrap-select/dist/css/bootstrap-select.min.css',
700
            'select2/dist/css/select2.min.css',
701
            'flag-icon-css/css/flag-icon.min.css'
702
        ];
703
704
        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...
705
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
706
        }
707
708
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
709
710
        if (api_is_global_chat_enabled()) {
711
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
712
        }
713
        $css_file_to_string = '';
714
        foreach ($css as $file) {
715
            $css_file_to_string .= api_get_css($file);
716
        }
717
718
        if (!$disable_js_and_css_files) {
719
            $this->assign('css_static_file_to_string', $css_file_to_string);
720
        }
721
    }
722
723
    /**
724
     *
725
     */
726
    public function setCSSEditor()
727
    {
728
        $cssEditor = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'editor.css');
729
        if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'editor.css')) {
730
            $cssEditor = api_get_path(WEB_CSS_PATH).$this->themeDir.'editor.css';
731
        }
732
733
        $this->assign('cssEditor', $cssEditor);
734
    }
735
736
    /**
737
     * Prepare custom CSS to be added at the very end of the <head> section
738
     * @return void
739
     * @see setCssFiles() for the mainstream CSS files
740
     */
741
    public function setCssCustomFiles()
742
    {
743
        global $disable_js_and_css_files;
744
        // chamilo CSS
745
        $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...
746
747
        // Base CSS
748
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.css');
749
750
        if ($this->show_learnpath) {
751
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
752
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
753
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
754
            }
755
        }
756
757
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
758
759
        $css_file_to_string = null;
760
        foreach ($css as $file) {
761
            $css_file_to_string .= api_get_css($file);
762
        }
763
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
764
        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...
765
            //hack in order to fix the actions buttons
766
            $css_file_to_string .= '<style>
767
                .td_actions a {
768
                    float:left;
769
                    width:100%;
770
                }
771
                .forum_message_left a {
772
                    float:left;
773
                    width:100%;
774
                }
775
                </style>';
776
        }
777
778
        $navigator_info = api_get_navigator();
779
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
780
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
781
        }
782
783
        if (!$disable_js_and_css_files) {
784
            $this->assign('css_custom_file_to_string', $css_file_to_string);
785
786
            $style_print = '';
787
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
788
                $style_print = api_get_css(
789
                    api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->theme.'/print.css'),
790
                    'print'
791
                );
792
            }
793
            $this->assign('css_style_print', $style_print);
794
        }
795
796
        // Logo
797
        $logo = return_logo($this->theme);
798
        $this->assign('logo', $logo);
799
        $this->assign('show_media_element', 1);
800
    }
801
802
    /**
803
     * Declare and define the template variable that will be used to load
804
     * javascript libraries in the header.
805
     */
806
    public function set_js_files()
807
    {
808
        global $disable_js_and_css_files, $htmlHeadXtra;
809
        $isoCode = api_get_language_isocode();
810
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
811
812
        if ($isoCode == 'en') {
813
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
814
        }
815
        // JS files
816
        $js_files = [
817
            'chosen/chosen.jquery.min.js'
818
        ];
819
820
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
821
822
        if (api_is_global_chat_enabled() || $viewBySession) {
823
            // Do not include the global chat in LP
824
            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...
825
                $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...
826
                $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...
827
            ) {
828
                $js_files[] = 'chat/js/chat.js';
829
            }
830
        }
831
832
        if (api_get_setting('accessibility_font_resize') == 'true') {
833
            $js_files[] = 'fontresize.js';
834
        }
835
836
        $js_file_to_string = '';
837
        $bowerJsFiles = [
838
            'modernizr/modernizr.js',
839
            'jquery/dist/jquery.min.js',
840
            'bootstrap/dist/js/bootstrap.min.js',
841
            'jquery-ui/jquery-ui.min.js',
842
            'moment/min/moment-with-locales.js',
843
            'bootstrap-daterangepicker/daterangepicker.js',
844
            'jquery-timeago/jquery.timeago.js',
845
            'mediaelement/build/mediaelement-and-player.min.js',
846
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
847
            'image-map-resizer/js/imageMapResizer.min.js',
848
            'jquery.scrollbar/jquery.scrollbar.min.js',
849
            'readmore-js/readmore.min.js',
850
            'bootstrap-select/dist/js/bootstrap-select.min.js',
851
            $selectLink,
852
            'select2/dist/js/select2.min.js',
853
            "select2/dist/js/i18n/$isoCode.js"
854
        ];
855
        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...
856
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
857
        }
858
859
        if (api_get_setting('include_asciimathml_script') == 'true') {
860
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
861
        }
862
863
        if ($isoCode != 'en') {
864
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
865
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
866
        }
867
868
        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...
869
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
870
        }
871
872
        $js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/chamilo.js"></script>'."\n";
873
        $js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'libs/ckeditor/ckeditor.js"></script>'."\n";
874
875
        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...
876
            //$js_file_to_string .= api_get_js($file);
877
        }
878
879
        // Loading email_editor js
880
        if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') {
881
            $template = $this->get_template('mail_editor/email_link.js.tpl');
882
            $js_file_to_string .= $this->fetch($template);
883
        }
884
885
        if (!$disable_js_and_css_files) {
886
            $this->assign('js_file_to_string', $js_file_to_string);
887
888
            $extra_headers = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
889
            //Adding jquery ui by default
890
            $extra_headers .= api_get_jquery_ui_js();
891
892
            //$extra_headers = '';
893
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
894
                foreach ($htmlHeadXtra as & $this_html_head) {
895
                    $extra_headers .= $this_html_head."\n";
896
                }
897
            }
898
            $this->assign('extra_headers', $extra_headers);
899
        }
900
    }
901
902
    /**
903
     * Special function to declare last-minute JS libraries which depend on
904
     * other things to be declared first. In particular, it might be useful
905
     * under IE9 with compatibility mode, which for some reason is getting
906
     * upset when a variable is used in a function (even if not used yet)
907
     * when this variable hasn't been defined yet.
908
     */
909
    public function set_js_files_post()
910
    {
911
        global $disable_js_and_css_files;
912
        $js_files = [];
913
        if (api_is_global_chat_enabled()) {
914
            //Do not include the global chat in LP
915
            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...
916
                $js_files[] = 'chat/js/chat.js';
917
            }
918
        }
919
        $js_file_to_string = null;
920
921
        foreach ($js_files as $js_file) {
922
            $js_file_to_string .= api_get_js($js_file);
923
        }
924
        if (!$disable_js_and_css_files) {
925
            $this->assign('js_file_to_string_post', $js_file_to_string);
926
        }
927
    }
928
929
    /**
930
     * Set header parameters
931
     * @param bool $sendHeaders send headers
932
     */
933
    private function set_header_parameters($sendHeaders)
934
    {
935
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
936
        $_course = api_get_course_info();
937
        $nameTools = $this->title;
938
        $navigation = return_navigation_array();
939
        $this->menu_navigation = $navigation['menu_navigation'];
940
941
        $this->assign('system_charset', api_get_system_encoding());
942
943
        if (isset($httpHeadXtra) && $httpHeadXtra) {
944
            foreach ($httpHeadXtra as & $thisHttpHead) {
945
                header($thisHttpHead);
946
            }
947
        }
948
949
        $this->assign(
950
            'online_button',
951
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
952
        );
953
        $this->assign(
954
            'offline_button',
955
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
956
        );
957
958
        // Get language iso-code for this page - ignore errors
959
        $this->assign('document_language', api_get_language_isocode());
960
961
        $course_title = isset($_course['name']) ? $_course['name'] : null;
962
963
        $title_list = [];
964
965
        $title_list[] = api_get_setting('Institution');
966
        $title_list[] = api_get_setting('siteName');
967
968
        if (!empty($course_title)) {
969
            $title_list[] = $course_title;
970
        }
971
        if ($nameTools != '') {
972
            $title_list[] = $nameTools;
973
        }
974
975
        $title_string = '';
976
        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...
977
            $title_string .= $title_list[$i];
978
            if (isset($title_list[$i + 1])) {
979
                $item = trim($title_list[$i + 1]);
980
                if (!empty($item)) {
981
                    $title_string .= ' - ';
982
                }
983
            }
984
        }
985
986
        $this->assign('title_string', $title_string);
987
988
        // Setting the theme and CSS files
989
        $this->setCssFiles();
990
        $this->set_js_files();
991
        $this->setCssCustomFiles();
992
993
        $browser = api_browser_support('check_browser');
994
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
995
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
996
            $this->assign('browser_specific_head', $browser_head);
997
        }
998
999
        // Implementation of prefetch.
1000
        // See http://cdn.chamilo.org/main/img/online.png for details
1001
        $prefetch = '';
1002
        if (!empty($_configuration['cdn_enable'])) {
1003
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1004
            foreach ($_configuration['cdn'] as $host => $exts) {
1005
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1006
            }
1007
        }
1008
1009
        $this->assign('prefetch', $prefetch);
1010
        $this->assign('text_direction', api_get_text_direction());
1011
        $this->assign('section_name', 'section-'.$this_section);
1012
1013
        // Default root chamilo favicon
1014
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1015
1016
        //Added to verify if in the current Chamilo Theme exist a favicon
1017
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1018
1019
        //If exist pick the current chamilo theme favicon
1020
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1021
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1022
        }
1023
1024
        if (api_is_multiple_url_enabled()) {
1025
            $access_url_id = api_get_current_access_url_id();
1026
            if ($access_url_id != -1) {
1027
                $url_info = api_get_access_url($access_url_id);
1028
                $url = api_remove_trailing_slash(
1029
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1030
                );
1031
                $clean_url = api_replace_dangerous_char($url);
1032
                $clean_url = str_replace('/', '-', $clean_url);
1033
                $clean_url .= '/';
1034
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1035
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1036
                //we create the new dir for the new sites
1037
                if (is_file($icon_real_homep.'favicon.ico')) {
1038
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1039
                }
1040
            }
1041
        }
1042
1043
        $this->assign('favico', $favico);
1044
        $this->setHelp();
1045
1046
        //@todo move this in the template
1047
        $rightFloatMenu = '';
1048
        $iconBug = Display::return_icon(
1049
            'bug.png',
1050
            get_lang('ReportABug'),
1051
            [],
1052
            ICON_SIZE_LARGE
1053
        );
1054
        if (api_get_setting('show_link_bug_notification') == 'true' && $this->user_is_logged_in) {
1055
            $rightFloatMenu = '<div class="report">
1056
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1057
                    '.$iconBug.'
1058
                </a>
1059
		        </div>';
1060
        }
1061
1062
        if (api_get_setting('show_link_ticket_notification') == 'true' && $this->user_is_logged_in) {
1063
            // by default is project_id = 1
1064
            $iconTicket = Display::return_icon(
1065
                'bug.png',
1066
                get_lang('Ticket'),
1067
                [],
1068
                ICON_SIZE_LARGE
1069
            );
1070
            $courseInfo = api_get_course_info();
1071
            $courseParams = '';
1072
            if (!empty($courseInfo)) {
1073
                $courseParams = api_get_cidreq();
1074
            }
1075
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id=1&'.$courseParams;
1076
            $rightFloatMenu .= '<div class="report">
1077
		        <a href="'.$url.'" target="_blank">
1078
                    '.$iconTicket.'
1079
                </a>
1080
		    </div>';
1081
        }
1082
1083
        $this->assign('bug_notification', $rightFloatMenu);
1084
1085
        $resize = '';
1086
        if (api_get_setting('accessibility_font_resize') == 'true') {
1087
            $resize .= '<div class="resize_font">';
1088
            $resize .= '<div class="btn-group">';
1089
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1090
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1091
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1092
            $resize .= '</div>';
1093
            $resize .= '</div>';
1094
        }
1095
        $this->assign('accessibility', $resize);
1096
1097
        // Preparing values for the menu
1098
1099
        // Logout link
1100
        $hideLogout = api_get_setting('hide_logout_button');
1101
        if ($hideLogout === 'true') {
1102
            $this->assign('logout_link', null);
1103
        } else {
1104
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1105
        }
1106
1107
        // Profile link
1108
        if (api_get_setting('allow_social_tool') == 'true') {
1109
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1110
        } else {
1111
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1112
        }
1113
1114
        $this->assign('profile_url', $profile_url);
1115
1116
        //Message link
1117
        $message_link = null;
1118
        $message_url = null;
1119
        if (api_get_setting('allow_message_tool') == 'true') {
1120
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1121
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1122
        }
1123
        $this->assign('message_link', $message_link);
1124
        $this->assign('message_url', $message_url);
1125
1126
        // Certificate Link
1127
1128
        $allow = api_get_configuration_value('hide_my_certificate_link');
1129
        if ($allow === false) {
1130
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1131
            $certificateLink = Display::url(
1132
                get_lang('MyCertificates'),
1133
                $certificateUrl
1134
            );
1135
            $this->assign('certificate_link', $certificateLink);
1136
            $this->assign('certificate_url', $certificateUrl);
1137
        }
1138
1139
        $institution = api_get_setting('Institution');
1140
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1141
1142
        $this->assign('portal_name', $portal_name);
1143
1144
        //Menu
1145
        $menu = menuArray();
1146
        $this->assign('menu', $menu);
1147
1148
        $breadcrumb = '';
1149
        // Hide breadcrumb in LP
1150
        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...
1151
            $breadcrumb = return_breadcrumb(
1152
                $interbreadcrumb,
1153
                $language_file,
1154
                $nameTools
1155
            );
1156
        }
1157
        $this->assign('breadcrumb', $breadcrumb);
1158
1159
        //Extra content
1160
        $extra_header = null;
1161
        if (!api_is_platform_admin()) {
1162
            $extra_header = trim(api_get_setting('header_extra_content'));
1163
        }
1164
        $this->assign('header_extra_content', $extra_header);
1165
1166
        if ($sendHeaders) {
1167
            header('Content-Type: text/html; charset='.api_get_system_encoding());
1168
            header(
1169
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1170
            );
1171
            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

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

1450
                    $this->assign('login_failed', $this::/** @scrutinizer ignore-call */ handleLoginFailed());
Loading history...
1451
                }
1452
            }
1453
        }
1454
    }
1455
1456
    /**
1457
     * @return string
1458
     */
1459
    public function handleLoginFailed()
1460
    {
1461
        $message = get_lang('InvalidId');
1462
1463
        if (!isset($_GET['error'])) {
1464
            if (api_is_self_registration_allowed()) {
1465
                $message = get_lang('InvalidForSelfRegistration');
1466
            }
1467
        } else {
1468
            switch ($_GET['error']) {
1469
                case '':
1470
                    if (api_is_self_registration_allowed()) {
1471
                        $message = get_lang('InvalidForSelfRegistration');
1472
                    }
1473
                    break;
1474
                case 'account_expired':
1475
                    $message = get_lang('AccountExpired');
1476
                    break;
1477
                case 'account_inactive':
1478
                    $message = get_lang('AccountInactive');
1479
1480
                    if (api_get_setting('allow_registration') === 'confirmation') {
1481
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1482
                        $message .= Display::url(
1483
                            get_lang('ReSendConfirmationMail'),
1484
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1485
                            ['class' => 'alert-link']
1486
                        );
1487
                    }
1488
                    break;
1489
                case 'user_password_incorrect':
1490
                    $message = get_lang('InvalidId');
1491
                    break;
1492
                case 'access_url_inactive':
1493
                    $message = get_lang('AccountURLInactive');
1494
                    break;
1495
                case 'wrong_captcha':
1496
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1497
                    break;
1498
                case 'blocked_by_captcha':
1499
                    $message = get_lang('AccountBlockedByCaptcha');
1500
                    break;
1501
                case 'multiple_connection_not_allowed':
1502
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1503
                    break;
1504
                case 'unrecognize_sso_origin':
1505
                    //$message = get_lang('SSOError');
1506
                    break;
1507
            }
1508
        }
1509
        return Display::return_message($message, 'error', false);
1510
    }
1511
1512
    /**
1513
     * @return string
1514
     */
1515
    public function displayLoginForm()
1516
    {
1517
        $form = new FormValidator(
1518
            'formLogin',
1519
            'POST',
1520
            api_get_path(WEB_PUBLIC_PATH).'login_check',
1521
            null,
1522
            null,
1523
            FormValidator::LAYOUT_BOX_NO_LABEL
1524
        );
1525
        $params = [
1526
            'id' => 'login',
1527
            'autofocus' => 'autofocus',
1528
            'icon' => 'user fa-fw',
1529
            'placeholder' => get_lang('UserName'),
1530
        ];
1531
        $browserAutoCapitalize= false;
1532
        // Avoid showing the autocapitalize option if the browser doesn't
1533
        // support it: this attribute is against the HTML5 standard
1534
        if (api_browser_support('autocapitalize')) {
1535
            $browserAutoCapitalize = false;
1536
            $params['autocapitalize'] = 'none';
1537
        }
1538
        $form->addText(
1539
            '_username',
1540
            get_lang('UserName'),
1541
            true,
1542
            $params
1543
        );
1544
        $params = [
1545
            'id' => 'password',
1546
            'icon' => 'lock fa-fw',
1547
            'placeholder' => get_lang('Pass'),
1548
        ];
1549
        if ($browserAutoCapitalize) {
1550
            $params['autocapitalize'] = 'none';
1551
        }
1552
        $form->addElement(
1553
            'password',
1554
            '_password',
1555
            get_lang('Pass'),
1556
            $params
1557
        );
1558
1559
        $token = Chamilo\CoreBundle\Framework\Container::$container->get('security.csrf.token_manager')->getToken('authenticate');
1560
        $form->addHidden('_csrf_token', $token->getValue());
1561
1562
        // Captcha
1563
        $captcha = api_get_setting('allow_captcha');
1564
        $allowCaptcha = $captcha === 'true';
1565
1566
        if ($allowCaptcha) {
1567
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1568
            if ($useCaptcha) {
1569
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1570
                $options = [
1571
                    'width' => 250,
1572
                    'height' => 90,
1573
                    'callback'     => $ajax.'&var='.basename(__FILE__, '.php'),
1574
                    'sessionVar'   => basename(__FILE__, '.php'),
1575
                    'imageOptions' => [
1576
                        'font_size' => 20,
1577
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1578
                        'font_file' => 'OpenSans-Regular.ttf',
1579
                        //'output' => 'gif'
1580
                    ]
1581
                ];
1582
1583
                // Minimum options using all defaults (including defaults for Image_Text):
1584
                //$options = array('callback' => 'qfcaptcha_image.php');
1585
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1586
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1587
1588
                $form->addElement(
1589
                    'text',
1590
                    'captcha',
1591
                    get_lang('EnterTheLettersYouSee')
1592
                );
1593
                $form->addRule(
1594
                    'captcha',
1595
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1596
                    'required',
1597
                    null,
1598
                    'client'
1599
                );
1600
                $form->addRule(
1601
                    'captcha',
1602
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1603
                    'CAPTCHA',
1604
                    $captcha_question
1605
                );
1606
            }
1607
        }
1608
1609
        $form->addButton(
1610
            'submitAuth',
1611
            get_lang('LoginEnter'),
1612
            null,
1613
            'primary',
1614
            null,
1615
            'btn-block'
1616
        );
1617
1618
        $html = $form->returnForm();
1619
        if (api_get_setting('openid_authentication') == 'true') {
1620
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1621
            $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

1621
            $html .= '<div>'./** @scrutinizer ignore-call */ openid_form().'</div>';
Loading history...
1622
        }
1623
1624
        return $html;
1625
    }
1626
1627
    /**
1628
     * Set administrator variables
1629
     */
1630
    private function setAdministratorParams()
1631
    {
1632
        $_admin = [
1633
            'email' => api_get_setting('emailAdministrator'),
1634
            'surname' => api_get_setting('administratorSurname'),
1635
            'name' => api_get_setting('administratorName'),
1636
            'telephone' => api_get_setting('administratorTelephone')
1637
        ];
1638
1639
        $this->assign('_admin', $_admin);
1640
    }
1641
1642
    /**
1643
     * Manage specific HTTP headers security
1644
     * @return void (prints headers directly)
1645
     */
1646
    private function addHTTPSecurityHeaders()
1647
    {
1648
        // Implementation of HTTP headers security, as suggested and checked
1649
        // by https://securityheaders.io/
1650
        // Enable these settings in configuration.php to use them on your site
1651
        // Strict-Transport-Security
1652
        $setting = api_get_configuration_value('security_strict_transport');
1653
        if (!empty($setting)) {
1654
            header('Strict-Transport-Security: '.$setting);
1655
        }
1656
        // Content-Security-Policy
1657
        $setting = api_get_configuration_value('security_content_policy');
1658
        if (!empty($setting)) {
1659
            header('Content-Security-Policy: '.$setting);
1660
        }
1661
        $setting = api_get_configuration_value('security_content_policy_report_only');
1662
        if (!empty($setting)) {
1663
            header('Content-Security-Policy-Report-Only: '.$setting);
1664
        }
1665
        // Public-Key-Pins
1666
        $setting = api_get_configuration_value('security_public_key_pins');
1667
        if (!empty($setting)) {
1668
            header('Public-Key-Pins: '.$setting);
1669
        }
1670
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1671
        if (!empty($setting)) {
1672
            header('Public-Key-Pins-Report-Only: '.$setting);
1673
        }
1674
        // X-Frame-Options
1675
        $setting = api_get_configuration_value('security_x_frame_options');
1676
        if (!empty($setting)) {
1677
            header('X-Frame-Options: '.$setting);
1678
        }
1679
        // X-XSS-Protection
1680
        $setting = api_get_configuration_value('security_xss_protection');
1681
        if (!empty($setting)) {
1682
            header('X-XSS-Protection: '.$setting);
1683
        }
1684
        // X-Content-Type-Options
1685
        $setting = api_get_configuration_value('security_x_content_type_options');
1686
        if (!empty($setting)) {
1687
            header('X-Content-Type-Options: '.$setting);
1688
        }
1689
        // Referrer-Policy
1690
        $setting = api_get_configuration_value('security_referrer_policy');
1691
        if (!empty($setting)) {
1692
            header('Referrer-Policy: '.$setting);
1693
        }
1694
        // end of HTTP headers security block
1695
    }
1696
1697
    /**
1698
     * Returns the tutors names for the current course in session
1699
     * Function to use in Twig templates
1700
     * @return string
1701
     */
1702
    public static function returnTutorsNames()
1703
    {
1704
        $em = Database::getManager();
1705
        $tutors = $em
1706
            ->createQuery('
1707
                SELECT u FROM ChamiloUserBundle:User u
1708
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1709
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1710
            ')
1711
            ->setParameters([
1712
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1713
                'session' => api_get_session_id(),
1714
                'course' => api_get_course_int_id()
1715
            ])
1716
            ->getResult();
1717
1718
        $names = [];
1719
1720
        /** @var User $tutor */
1721
        foreach ($tutors as $tutor) {
1722
            $names[] = $tutor->getCompleteName();
1723
        }
1724
1725
        return implode(CourseManager::USER_SEPARATOR, $names);
1726
    }
1727
1728
    /**s
1729
     * Returns the teachers name for the current course
1730
     * Function to use in Twig templates
1731
     * @return string
1732
     */
1733
    public static function returnTeachersNames()
1734
    {
1735
        $em = Database::getManager();
1736
        $teachers = $em
1737
            ->createQuery('
1738
                SELECT u FROM ChamiloUserBundle:User u
1739
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1740
                WHERE cu.status = :teacher_status AND cu.course = :course
1741
            ')
1742
            ->setParameters([
1743
                'teacher_status' => User::COURSE_MANAGER,
1744
                'course' => api_get_course_int_id()
1745
            ])
1746
            ->getResult();
1747
1748
        $names = [];
1749
1750
        /** @var User $teacher */
1751
        foreach ($teachers as $teacher) {
1752
            $names[] = $teacher->getCompleteName();
1753
        }
1754
1755
        return implode(CourseManager::USER_SEPARATOR, $names);
1756
    }
1757
1758
    /**
1759
     * @param int $code
1760
     */
1761
    public function setResponseCode($code)
1762
    {
1763
        $this->responseCode = $code;
1764
    }
1765
1766
    /**
1767
     * @param string $code
1768
     */
1769
    public function getResponseCode()
1770
    {
1771
        return $this->responseCode;
1772
    }
1773
}
1774