Template::getThemeDir()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
7
use Chamilo\UserBundle\Entity\User;
8
9
/**
10
 * Class Template.
11
 *
12
 * @author Julio Montoya <[email protected]>
13
 *
14
 * @todo better organization of the class, methods and variables
15
 */
16
class Template
17
{
18
    /**
19
     * The Template folder name see main/template.
20
     *
21
     * @var string
22
     */
23
    public $templateFolder = 'default';
24
25
    /**
26
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
27
     * This variable is set from the database.
28
     *
29
     * @var string
30
     */
31
    public $theme = '';
32
33
    /**
34
     * @var string
35
     */
36
    public $preview_theme = '';
37
    public $title = null;
38
    public $show_header;
39
    public $show_footer;
40
    public $help;
41
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
42
    public $show_learnpath = false; // This is a learnpath section or not?
43
    public $plugin = null;
44
    public $course_id = null;
45
    public $user_is_logged_in = false;
46
    public $twig = null;
47
48
    /* Loads chamilo plugins */
49
    public $load_plugins = false;
50
    public $params = [];
51
    public $force_plugin_load = false;
52
    public $responseCode = 0;
53
    private $themeDir;
54
55
    /**
56
     * @param string $title
57
     * @param bool   $show_header
58
     * @param bool   $show_footer
59
     * @param bool   $show_learnpath
60
     * @param bool   $hide_global_chat
61
     * @param bool   $load_plugins
62
     * @param int    $responseCode
63
     * @param bool   $sendHeaders      send http headers or not
64
     */
65
    public function __construct(
66
        $title = '',
67
        $show_header = true,
68
        $show_footer = true,
69
        $show_learnpath = false,
70
        $hide_global_chat = false,
71
        $load_plugins = true,
72
        $sendHeaders = true,
73
        $responseCode = 0
74
    ) {
75
        // Page title
76
        $this->title = $title;
77
        $this->show_learnpath = $show_learnpath;
78
        $this->setResponseCode($responseCode);
79
80
        if (empty($this->show_learnpath)) {
81
            $origin = api_get_origin();
82
            if ($origin === 'learnpath') {
83
                $this->show_learnpath = true;
84
                $show_footer = false;
85
                $show_header = false;
86
            }
87
        }
88
        $this->hide_global_chat = $hide_global_chat;
89
        $this->load_plugins = $load_plugins;
90
91
        $template_paths = [
92
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
93
            api_get_path(SYS_CODE_PATH).'template', //template folder
94
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
95
        ];
96
97
        $urlId = api_get_current_access_url_id();
98
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
99
100
        if (!is_dir($cache_folder)) {
101
            mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
102
        }
103
104
        $loader = new Twig_Loader_Filesystem($template_paths);
105
106
        $isTestMode = api_get_setting('server_type') === 'test';
107
108
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
109
        if ($isTestMode) {
110
            $options = [
111
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
112
                'autoescape' => false,
113
                'debug' => true,
114
                'auto_reload' => true,
115
                'optimizations' => 0,
116
                // turn on optimizations with -1
117
                'strict_variables' => false,
118
                //If set to false, Twig will silently ignore invalid variables
119
            ];
120
        } else {
121
            $options = [
122
                'cache' => $cache_folder,
123
                //path to the cache folder
124
                'autoescape' => false,
125
                'debug' => false,
126
                'auto_reload' => false,
127
                'optimizations' => -1,
128
                // turn on optimizations with -1
129
                'strict_variables' => false,
130
                //If set to false, Twig will silently ignore invalid variables
131
            ];
132
        }
133
134
        $this->twig = new Twig_Environment($loader, $options);
135
136
        if ($isTestMode) {
137
            $this->twig->addExtension(new Twig_Extension_Debug());
138
        }
139
140
        // Twig filters setup
141
        $filters = [
142
            'var_dump',
143
            'get_plugin_lang',
144
            'get_lang',
145
            'api_get_path',
146
            'api_get_local_time',
147
            'api_convert_and_format_date',
148
            'api_is_allowed_to_edit',
149
            'api_get_user_info',
150
            'api_get_configuration_value',
151
            'api_get_setting',
152
            'api_get_course_setting',
153
            'api_get_plugin_setting',
154
            [
155
                'name' => 'return_message',
156
                'callable' => 'Display::return_message_and_translate',
157
            ],
158
            [
159
                'name' => 'display_page_header',
160
                'callable' => 'Display::page_header_and_translate',
161
            ],
162
            [
163
                'name' => 'display_page_subheader',
164
                'callable' => 'Display::page_subheader_and_translate',
165
            ],
166
            [
167
                'name' => 'icon',
168
                'callable' => 'Display::get_icon_path',
169
            ],
170
            [
171
                'name' => 'img',
172
                'callable' => 'Display::get_image',
173
            ],
174
            [
175
                'name' => 'format_date',
176
                'callable' => 'api_format_date',
177
            ],
178
            [
179
                'name' => 'get_template',
180
                'callable' => 'api_find_template',
181
            ],
182
            [
183
                'name' => 'date_to_time_ago',
184
                'callable' => 'Display::dateToStringAgoAndLongDate',
185
            ],
186
            [
187
                'name' => 'remove_xss',
188
                'callable' => 'Security::remove_XSS',
189
            ],
190
        ];
191
192
        foreach ($filters as $filter) {
193
            if (is_array($filter)) {
194
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
195
            } else {
196
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
197
            }
198
        }
199
200
        $functions = [
201
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
202
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
203
            ['name' => 'api_is_platform_admin', 'callable' => 'api_is_platform_admin'],
204
        ];
205
206
        foreach ($functions as $function) {
207
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
208
        }
209
210
        // Setting system variables
211
        $this->set_system_parameters();
212
213
        // Setting user variables
214
        $this->set_user_parameters();
215
216
        // Setting course variables
217
        $this->set_course_parameters();
218
219
        // Setting administrator variables
220
        $this->setAdministratorParams();
221
        //$this->setCSSEditor();
222
223
        // Header and footer are showed by default
224
        $this->set_footer($show_footer);
225
        $this->set_header($show_header);
226
227
        // Extra class for the main cm-content div
228
        global $htmlContentExtraClass;
229
        $this->setExtraContentClass($htmlContentExtraClass);
230
231
        $this->set_header_parameters($sendHeaders);
232
        $this->set_footer_parameters();
233
234
        $defaultStyle = api_get_configuration_value('default_template');
235
        if (!empty($defaultStyle)) {
236
            $this->templateFolder = $defaultStyle;
0 ignored issues
show
Documentation Bug introduced by
It seems like $defaultStyle can also be of type boolean. However, the property $templateFolder is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
237
        }
238
239
        $this->assign('template', $this->templateFolder);
240
        $this->assign('locale', api_get_language_isocode());
241
        $this->assign('login_class', null);
242
243
        $allow = api_get_configuration_value('show_language_selector_in_menu');
244
        if ($allow) {
245
            $this->assign('language_form', api_display_language_form());
246
        }
247
248
        if (api_get_configuration_value('notification_event')) {
249
            $this->assign('notification_event', '1');
250
        }
251
252
        // Chamilo plugins
253
        if ($this->show_header) {
254
            if ($this->load_plugins) {
255
                $this->plugin = new AppPlugin();
256
257
                //1. Showing installed plugins in regions
258
                $pluginRegions = $this->plugin->get_plugin_regions();
259
                foreach ($pluginRegions as $region) {
260
                    $this->set_plugin_region($region);
261
                }
262
263
                //2. Loading the course plugin info
264
                global $course_plugin;
265
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
266
                    //Load plugin get_langs
267
                    $this->plugin->load_plugin_lang_variables($course_plugin);
268
                }
269
            }
270
        }
271
    }
272
273
    /**
274
     * Return the item's url key:.
275
     *
276
     *      c_id=xx&id=xx
277
     *
278
     * @param object $item
279
     *
280
     * @return string
281
     */
282
    public static function key($item)
283
    {
284
        $id = isset($item->id) ? $item->id : null;
285
        $c_id = isset($item->c_id) ? $item->c_id : null;
286
        $result = '';
287
        if ($c_id) {
288
            $result = "c_id=$c_id";
289
        }
290
        if ($id) {
291
            if ($result) {
292
                $result .= "&amp;id=$id";
293
            } else {
294
                $result .= "&amp;id=$id";
295
            }
296
        }
297
298
        return $result;
299
    }
300
301
    /**
302
     * @param string $helpInput
303
     */
304
    public function setHelp($helpInput = null)
305
    {
306
        if (!empty($helpInput)) {
307
            $help = $helpInput;
308
        } else {
309
            $help = $this->help;
310
        }
311
312
        $content = '';
313
        if (api_get_setting('enable_help_link') == 'true') {
314
            if (!empty($help)) {
315
                $help = Security::remove_XSS($help);
316
                $content = '<div class="help">';
317
                $content .= Display::url(
318
                    Display::return_icon('help.large.png', get_lang('Help')),
319
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
320
                    [
321
                        'class' => 'ajax',
322
                        'data-title' => get_lang('Help'),
323
                    ]
324
                );
325
                $content .= '</div>';
326
            }
327
        }
328
        $this->assign('help_content', $content);
329
    }
330
331
    /**
332
     * Use template system to parse the actions menu.
333
     *
334
     * @todo finish it!
335
     */
336
    public function set_actions($actions)
337
    {
338
        $action_string = '';
339
        if (!empty($actions)) {
340
            foreach ($actions as $action) {
341
                $action_string .= $action;
342
            }
343
        }
344
        $this->assign('actions', $actions);
345
    }
346
347
    /**
348
     * Shortcut to display a 1 col layout (index.php).
349
     * */
350
    public function display_one_col_template(bool $clearFlashMessages = true)
351
    {
352
        $tpl = $this->get_template('layout/layout_1_col.tpl');
353
        $this->display($tpl, $clearFlashMessages);
354
    }
355
356
    /**
357
     * Shortcut to display a 2 col layout (userportal.php).
358
     */
359
    public function display_two_col_template()
360
    {
361
        $tpl = $this->get_template('layout/layout_2_col.tpl');
362
        $this->display($tpl);
363
    }
364
365
    /**
366
     * Displays an empty template.
367
     */
368
    public function display_blank_template()
369
    {
370
        $tpl = $this->get_template('layout/blank.tpl');
371
        $this->display($tpl);
372
    }
373
374
    /**
375
     * Displays an empty template.
376
     */
377
    public function displayBlankTemplateNoHeader()
378
    {
379
        $tpl = $this->get_template('layout/blank_no_header.tpl');
380
        $this->display($tpl);
381
    }
382
383
    /**
384
     * Displays an empty template.
385
     */
386
    public function display_no_layout_template()
387
    {
388
        $tpl = $this->get_template('layout/no_layout.tpl');
389
        $this->display($tpl);
390
    }
391
392
    /**
393
     * Sets the footer visibility.
394
     *
395
     * @param bool true if we show the footer
396
     */
397
    public function set_footer($status)
398
    {
399
        $this->show_footer = $status;
400
        $this->assign('show_footer', $status);
401
    }
402
403
    /**
404
     * return true if toolbar has to be displayed for user.
405
     *
406
     * @return bool
407
     */
408
    public static function isToolBarDisplayedForUser()
409
    {
410
        //Toolbar
411
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
412
        $show_toolbar = false;
413
414
        switch ($show_admin_toolbar) {
415
            case 'do_not_show':
416
                break;
417
            case 'show_to_admin':
418
                if (api_is_platform_admin()) {
419
                    $show_toolbar = true;
420
                }
421
                break;
422
            case 'show_to_admin_and_teachers':
423
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
424
                    $show_toolbar = true;
425
                }
426
                break;
427
            case 'show_to_all':
428
                $show_toolbar = true;
429
                break;
430
        }
431
432
        return $show_toolbar;
433
    }
434
435
    /**
436
     * Sets the header visibility.
437
     *
438
     * @param bool true if we show the header
439
     */
440
    public function set_header($status)
441
    {
442
        $this->show_header = $status;
443
        $this->assign('show_header', $status);
444
445
        $show_toolbar = 0;
446
447
        if (self::isToolBarDisplayedForUser()) {
448
            $show_toolbar = 1;
449
        }
450
451
        $this->assign('show_toolbar', $show_toolbar);
452
453
        // Only if course is available
454
        $courseToolBar = '';
455
        $origin = api_get_origin();
456
        $show_course_navigation_menu = '';
457
        if (!empty($this->course_id) && $this->user_is_logged_in) {
458
            if ($origin !== 'iframe' && $origin !== 'embeddable' && api_get_setting('show_toolshortcuts') !== 'false') {
459
                // Course toolbar
460
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
461
            }
462
            if (api_get_setting('show_navigation_menu') != 'false') {
463
                // Course toolbar
464
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
465
            }
466
        }
467
        $this->assign('show_course_shortcut', $courseToolBar);
468
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
469
    }
470
471
    /**
472
     * Sets an extra class for the main cm-content div.
473
     * To use, give a new row to $htmlContentExtraClass like so: `$htmlContentExtraClass[] = 'feature-item-user-skill-on';`
474
     * before any Display::display_header() call.
475
     */
476
    public function setExtraContentClass($htmlContentExtraClass): void
477
    {
478
        if (empty($htmlContentExtraClass)) {
479
            $extraClass = '';
480
        } else {
481
            if (is_array($htmlContentExtraClass)) {
482
                $extraClass = implode(' ', $htmlContentExtraClass);
483
            } else {
484
                $extraClass = $htmlContentExtraClass;
485
            }
486
            $extraClass = Security::remove_XSS($extraClass);
487
            $extraClass = trim($extraClass);
488
            $extraClass = ' class="'.$extraClass.'"';
489
        }
490
        $this->assign('html_content_extra_class', $extraClass);
491
    }
492
493
    /**
494
     * Returns the sub-folder and filename for the given tpl file.
495
     *
496
     * If template not found in overrides/ or custom template folder, the default template will be used.
497
     *
498
     * @param string $name
499
     *
500
     * @return string
501
     */
502
    public static function findTemplateFilePath($name)
503
    {
504
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
505
506
        // Check if the tpl file is present in the main/template/overrides/ dir
507
        // Overrides is a special directory meant for temporary template
508
        // customization. It must be taken into account before anything else
509
        if (is_readable($sysTemplatePath."overrides/$name")) {
510
            return "overrides/$name";
511
        }
512
513
        $defaultFolder = api_get_configuration_value('default_template');
514
515
        // If a template folder has been manually defined, search for the right
516
        // file, and if not found, go for the same file in the default template
517
        if ($defaultFolder && $defaultFolder != 'default') {
518
            // Avoid missing template error, use the default file.
519
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
520
                return "$defaultFolder/$name";
521
            }
522
        }
523
524
        return "default/$name";
525
    }
526
527
    /**
528
     * Call non-static for Template::findTemplateFilePath.
529
     *
530
     * @see Template::findTemplateFilePath()
531
     *
532
     * @param string $name
533
     *
534
     * @return string
535
     */
536
    public function get_template($name)
537
    {
538
        return api_find_template($name);
539
    }
540
541
    /**
542
     * Get CSS themes sub-directory.
543
     *
544
     * @param string $theme
545
     *
546
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
547
     */
548
    public static function getThemeDir($theme)
549
    {
550
        $themeDir = 'themes/'.$theme.'/';
551
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
552
        if (!empty($virtualTheme)) {
553
            $virtualThemeList = api_get_themes(true);
554
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
555
            if ($isVirtualTheme) {
556
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
557
            }
558
        }
559
560
        return $themeDir;
561
    }
562
563
    /**
564
     * Set system parameters from api_get_configuration into _s array for use in TPLs
565
     * Also fills the _p array from getWebPaths().
566
     *
567
     * @uses \self::getWebPaths()
568
     */
569
    public function set_system_parameters()
570
    {
571
        // Get the interface language from global.inc.php
572
        global $language_interface;
573
        $this->theme = api_get_visual_theme();
574
        if (!empty($this->preview_theme)) {
575
            $this->theme = $this->preview_theme;
576
        }
577
578
        $this->themeDir = self::getThemeDir($this->theme);
579
580
        // Setting app paths/URLs
581
        $this->assign('_p', $this->getWebPaths());
582
583
        // Here we can add system parameters that can be use in any template
584
        $_s = [
585
            'software_name' => api_get_configuration_value('software_name'),
586
            'system_version' => api_get_configuration_value('system_version'),
587
            'site_name' => api_get_setting('siteName'),
588
            'institution' => api_get_setting('Institution'),
589
            'institution_url' => api_get_setting('InstitutionUrl'),
590
            'date' => api_format_date('now', DATE_FORMAT_LONG),
591
            'timezone' => api_get_timezone(),
592
            'gamification_mode' => api_get_setting('gamification_mode'),
593
            'language_interface' => $language_interface,
594
        ];
595
        $this->assign('_s', $_s);
596
    }
597
598
    /**
599
     * Set theme, include mainstream CSS files.
600
     *
601
     * @see setCssCustomFiles() for additional CSS sheets
602
     */
603
    public function setCssFiles()
604
    {
605
        global $disable_js_and_css_files;
606
        $css = [];
607
608
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
609
        $webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
610
611
        // Default CSS Bootstrap
612
        $bowerCSSFiles = [
613
            'fontawesome/css/font-awesome.min.css',
614
            'jquery-ui/themes/smoothness/theme.css',
615
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
616
            'mediaelement/build/mediaelementplayer.min.css',
617
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
618
            'bootstrap/dist/css/bootstrap.min.css',
619
            'jquery.scrollbar/jquery.scrollbar.css',
620
            'bootstrap-daterangepicker/daterangepicker.css',
621
            'bootstrap-select/dist/css/bootstrap-select.min.css',
622
            'select2/dist/css/select2.min.css',
623
        ];
624
625
        $hide = api_get_configuration_value('hide_flag_language_switcher');
626
627
        if ($hide === false) {
628
            $bowerCSSFiles[] = 'flag-icon-css/css/flag-icon.min.css';
629
        }
630
631
        foreach ($bowerCSSFiles as $file) {
632
            $css[] = api_get_cdn_path($webPublicPath.'assets/'.$file);
633
        }
634
635
        $isVrViewEnabled = Display::isVrViewEnabled();
636
637
        if ($isVrViewEnabled) {
638
            $css[] = $webJsPath.'mediaelement/plugins/vrview/vrview.css';
639
        }
640
641
        $features = api_get_configuration_value('video_features');
642
        $defaultFeatures = [
643
            'playpause',
644
            'current',
645
            'progress',
646
            'duration',
647
            'tracks',
648
            'volume',
649
            'fullscreen',
650
            'markersrolls',
651
        ];
652
653
        if ($isVrViewEnabled) {
654
            $defaultFeatures[] = 'vrview';
655
        }
656
657
        if (!empty($features) && isset($features['features'])) {
658
            foreach ($features['features'] as $feature) {
659
                if ($feature === 'vrview') {
660
                    continue;
661
                }
662
                $css[] = $webJsPath."mediaelement/plugins/$feature/$feature.min.css";
663
                $defaultFeatures[] = $feature;
664
            }
665
        }
666
667
        $css[] = $webJsPath.'chosen/chosen.css';
668
669
        if (api_is_global_chat_enabled()) {
670
            $css[] = $webJsPath.'chat/css/chat.css';
671
        }
672
        $css_file_to_string = '';
673
        foreach ($css as $file) {
674
            $css_file_to_string .= api_get_css($file);
675
        }
676
677
        if (!$disable_js_and_css_files) {
678
            $this->assign('css_static_file_to_string', $css_file_to_string);
679
        }
680
681
        $defaultFeatures = implode("','", $defaultFeatures);
682
        $this->assign('video_features', $defaultFeatures);
683
    }
684
685
    /**
686
     * Prepare custom CSS to be added at the very end of the <head> section.
687
     *
688
     * @see setCssFiles() for the mainstream CSS files
689
     */
690
    public function setCssCustomFiles()
691
    {
692
        global $disable_js_and_css_files;
693
        // Base CSS
694
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.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...
695
696
        if ($this->show_learnpath) {
697
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
698
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
699
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
700
            }
701
        }
702
        if (CustomPages::enabled()) {
703
            $cssCustomPage = api_get_path(SYS_CSS_PATH).$this->themeDir."custompage.css";
704
            if (is_file($cssCustomPage)) {
705
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'custompage.css';
706
            } else {
707
                $css[] = api_get_path(WEB_CSS_PATH).'custompage.css';
708
            }
709
        }
710
711
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
712
        $css[] = api_get_cdn_path(ChamiloApi::getEditorBlockStylePath());
713
714
        $css_file_to_string = null;
715
        foreach ($css as $file) {
716
            $css_file_to_string .= api_get_css($file);
717
        }
718
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
719
        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...
720
            //hack in order to fix the actions buttons
721
            $css_file_to_string .= '<style>
722
                .td_actions a {
723
                    float:left;
724
                    width:100%;
725
                }
726
                .forum_message_left a {
727
                    float:left;
728
                    width:100%;
729
                }
730
                </style>';
731
        }
732
733
        $navigator_info = api_get_navigator();
734
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
735
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
736
        }
737
738
        if (!$disable_js_and_css_files) {
739
            $this->assign('css_custom_file_to_string', $css_file_to_string);
740
741
            $style_print = api_get_css(
742
                api_get_print_css(false, true),
743
                'print'
744
            );
745
            $this->assign('css_style_print', $style_print);
746
        }
747
748
        // Logo
749
        $logo = return_logo($this->theme);
750
        $logoPdf = return_logo($this->theme, false);
751
        $this->assign('logo', $logo);
752
        $this->assign('logo_pdf', $logoPdf);
753
        $this->assign('show_media_element', 1);
754
    }
755
756
    /**
757
     * Declare and define the template variable that will be used to load
758
     * javascript libraries in the header.
759
     */
760
    public function set_js_files()
761
    {
762
        global $disable_js_and_css_files, $htmlHeadXtra;
763
        $isoCode = api_get_language_isocode();
764
        $isVrViewEnabled = Display::isVrViewEnabled();
765
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
766
767
        if ($isoCode == 'en') {
768
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
769
        }
770
        // JS files
771
        $js_files = [];
772
        $js_files[] = 'chosen/chosen.jquery.min.js';
773
774
        if ($isVrViewEnabled) {
775
            $js_files[] = 'mediaelement/plugins/vrview/vrview.js';
776
        }
777
778
        $js_files[] = 'mediaelement/plugins/markersrolls/markersrolls.min.js';
779
780
        if (api_get_setting('accessibility_font_resize') === 'true') {
781
            $js_files[] = 'fontresize.js';
782
        }
783
784
        $js_file_to_string = '';
785
        $bowerJsFiles = [
786
            'modernizr/modernizr.js',
787
            'jquery/dist/jquery.min.js',
788
            'bootstrap/dist/js/bootstrap.min.js',
789
            'jquery-ui/jquery-ui.min.js',
790
            'en' !== $isoCode ? "jquery-ui/ui/minified/i18n/datepicker-$isoCode.js" : null,
791
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
792
            'moment/min/moment-with-locales.js',
793
            'bootstrap-daterangepicker/daterangepicker.js',
794
            'jquery-timeago/jquery.timeago.js',
795
            'mediaelement/build/mediaelement-and-player.min.js',
796
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
797
            'en' !== $isoCode ? "jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-$isoCode.js" : null,
798
            'image-map-resizer/js/imageMapResizer.min.js',
799
            'jquery.scrollbar/jquery.scrollbar.min.js',
800
            'readmore-js/readmore.min.js',
801
            'bootstrap-select/dist/js/bootstrap-select.min.js',
802
            $selectLink,
803
            'select2/dist/js/select2.min.js',
804
            "select2/dist/js/i18n/$isoCode.js",
805
            'js-cookie/src/js.cookie.js',
806
        ];
807
808
        if ($renderers = api_get_configuration_sub_value('video_player_renderers/renderers')) {
809
            foreach ($renderers as $renderName) {
810
                if ('youtube' === $renderName) {
811
                    continue;
812
                }
813
814
                $bowerJsFiles[] = "mediaelement/build/renderers/$renderName.min.js";
815
            }
816
        }
817
818
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
819
820
        if ($viewBySession || api_is_global_chat_enabled()) {
821
            // Do not include the global chat in LP
822
            if ($this->show_learnpath == false &&
823
                $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...
824
                $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...
825
            ) {
826
                $js_files[] = 'chat/js/chat.js';
827
                $bowerJsFiles[] = 'linkifyjs/linkify.js';
828
                $bowerJsFiles[] = 'linkifyjs/linkify-jquery.js';
829
            }
830
        }
831
832
        $features = api_get_configuration_value('video_features');
833
        if (!empty($features) && isset($features['features'])) {
834
            foreach ($features['features'] as $feature) {
835
                if ($feature === 'vrview') {
836
                    continue;
837
                }
838
                $js_files[] = "mediaelement/plugins/$feature/$feature.min.js";
839
            }
840
        }
841
842
        if (CHAMILO_LOAD_WYSIWYG === true) {
843
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
844
        }
845
846
        if (api_get_setting('include_asciimathml_script') === 'true') {
847
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
848
        }
849
850
        // If not English and the language is supported by timepicker, localize
851
        $assetsPath = api_get_path(SYS_PUBLIC_PATH).'assets/';
852
        if ($isoCode != 'en') {
853
            if (is_file($assetsPath.'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js') && is_file($assetsPath.'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js')) {
854
                $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
855
                $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
856
            }
857
        }
858
859
        $bowerJsFiles = array_filter($bowerJsFiles);
860
861
        foreach ($bowerJsFiles as $file) {
862
            $js_file_to_string .= '<script src="'.api_get_cdn_path(api_get_path(WEB_PUBLIC_PATH).'assets/'.$file).'"></script>'."\n";
863
        }
864
865
        foreach ($js_files as $file) {
866
            $js_file_to_string .= api_get_js($file);
867
        }
868
869
        // Loading email_editor js
870
        if (api_get_setting('allow_email_editor') === 'true') {
871
            $link = 'email_editor.php';
872
            if (!api_is_anonymous()) {
873
                $this->assign('email_editor', $link);
874
                $template = $this->get_template('mail_editor/email_link.js.tpl');
875
                $js_file_to_string .= $this->fetch($template);
876
            } else {
877
                if (api_get_configuration_value('allow_email_editor_for_anonymous')) {
878
                    $link = 'email_editor_external.php';
879
                    $this->assign('email_editor', $link);
880
                    $template = $this->get_template('mail_editor/email_link.js.tpl');
881
                    $js_file_to_string .= $this->fetch($template);
882
                }
883
            }
884
        }
885
886
        if (!$disable_js_and_css_files) {
887
            $this->assign('js_file_to_string', $js_file_to_string);
888
889
            $extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
890
            // Adding jquery ui by default
891
            $extraHeaders .= api_get_jquery_ui_js();
892
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
893
                foreach ($htmlHeadXtra as &$this_html_head) {
894
                    $extraHeaders .= $this_html_head."\n";
895
                }
896
            }
897
898
            $ajax = api_get_path(WEB_AJAX_PATH);
899
            $courseId = api_get_course_id();
900
            if (empty($courseId)) {
901
                $courseLogoutCode = '
902
                <script>
903
                function courseLogout() {
904
                }
905
                </script>';
906
            } else {
907
                $courseLogoutCode = "
908
                <script>
909
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
910
                function courseLogout() {
911
                    $.ajax({
912
                        async : false,
913
                        url: logOutUrl,
914
                        success: function (data) {
915
                            return 1;
916
                        }
917
                    });
918
                }
919
                </script>";
920
            }
921
922
            $extraHeaders .= $courseLogoutCode;
923
            $this->assign('extra_headers', $extraHeaders);
924
        }
925
    }
926
927
    /**
928
     * Special function to declare last-minute JS libraries which depend on
929
     * other things to be declared first. In particular, it might be useful
930
     * under IE9 with compatibility mode, which for some reason is getting
931
     * upset when a variable is used in a function (even if not used yet)
932
     * when this variable hasn't been defined yet.
933
     */
934
    public function set_js_files_post()
935
    {
936
        global $disable_js_and_css_files;
937
        $js_files = [];
938
        $bower = '';
939
        if (api_is_global_chat_enabled()) {
940
            //Do not include the global chat in LP
941
            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...
942
                $js_files[] = 'chat/js/chat.js';
943
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify.js"></script>';
944
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify-jquery.js"></script>';
945
            }
946
        }
947
        $js_file_to_string = '';
948
        foreach ($js_files as $js_file) {
949
            $js_file_to_string .= api_get_js($js_file);
950
        }
951
        if (!$disable_js_and_css_files) {
952
            $this->assign('js_file_to_string_post', $js_file_to_string.$bower);
953
        }
954
    }
955
956
    /**
957
     * Show header template.
958
     */
959
    public function show_header_template()
960
    {
961
        $tpl = $this->get_template('layout/show_header.tpl');
962
        $this->display($tpl);
963
    }
964
965
    /**
966
     * Show footer template.
967
     */
968
    public function show_footer_template()
969
    {
970
        $tpl = $this->get_template('layout/show_footer.tpl');
971
        $this->display($tpl);
972
    }
973
974
    /**
975
     * Sets the plugin content in a template variable.
976
     *
977
     * @param string $pluginRegion
978
     */
979
    public function set_plugin_region($pluginRegion)
980
    {
981
        if (!empty($pluginRegion)) {
982
            $regionContent = $this->plugin->load_region(
983
                $pluginRegion,
984
                $this,
985
                $this->force_plugin_load
986
            );
987
988
            $pluginList = $this->plugin->getInstalledPlugins(false);
989
            foreach ($pluginList as $plugin_name) {
990
                // The plugin_info variable is available inside the plugin index
991
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
992
993
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
994
                    $courseInfo = api_get_course_info();
995
                    if (!empty($courseInfo)) {
996
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
997
                            /** @var Plugin $plugin */
998
                            $plugin = $pluginInfo['obj'];
999
                            $regionContent .= $plugin->renderRegion($pluginRegion);
1000
                        }
1001
                    }
1002
                } else {
1003
                    continue;
1004
                }
1005
            }
1006
1007
            if (!empty($regionContent)) {
1008
                $this->assign('plugin_'.$pluginRegion, $regionContent);
1009
            } else {
1010
                $this->assign('plugin_'.$pluginRegion, null);
1011
            }
1012
        }
1013
1014
        return null;
1015
    }
1016
1017
    /**
1018
     * @param string $template
1019
     *
1020
     * @return string
1021
     */
1022
    public function fetch($template = null)
1023
    {
1024
        $template = $this->twig->loadTemplate($template);
1025
1026
        return $template->render($this->params);
1027
    }
1028
1029
    /**
1030
     * @param string $variable
1031
     * @param mixed  $value
1032
     */
1033
    public function assign($variable, $value = '')
1034
    {
1035
        $this->params[$variable] = $value;
1036
    }
1037
1038
    /**
1039
     * Render the template.
1040
     *
1041
     * @param string $template           The template path
1042
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
1043
     */
1044
    public function display($template, $clearFlashMessages = true)
1045
    {
1046
        $this->assign('page_origin', api_get_origin());
1047
        $this->assign('flash_messages', Display::getFlashToString());
1048
1049
        if ($clearFlashMessages) {
1050
            Display::cleanFlashMessages();
1051
        }
1052
1053
        echo $this->twig->render($template, $this->params);
1054
    }
1055
1056
    /**
1057
     * Adds a body class for login pages.
1058
     */
1059
    public function setLoginBodyClass()
1060
    {
1061
        $this->assign('login_class', 'section-login');
1062
    }
1063
1064
    /**
1065
     * The theme that will be used if the database is not working.
1066
     *
1067
     * @return string
1068
     */
1069
    public static function getThemeFallback()
1070
    {
1071
        $theme = api_get_configuration_value('theme_fallback');
1072
        if (empty($theme)) {
1073
            $theme = 'chamilo';
1074
        }
1075
1076
        return $theme;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $theme also could return the type boolean which is incompatible with the documented return type string.
Loading history...
1077
    }
1078
1079
    /**
1080
     * @param bool|true $setLoginForm
1081
     */
1082
    public function setLoginForm($setLoginForm = true)
1083
    {
1084
        global $loginFailed;
1085
        $userId = api_get_user_id();
1086
        if (!($userId) || api_is_anonymous($userId)) {
1087
            // Only display if the user isn't logged in.
1088
            $this->assign(
1089
                'login_language_form',
1090
                api_display_language_form(true, true)
1091
            );
1092
            if ($setLoginForm) {
1093
                $this->assign('login_form', $this->displayLoginForm());
1094
1095
                if ($loginFailed) {
1096
                    $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

1096
                    $this->assign('login_failed', $this::/** @scrutinizer ignore-call */ handleLoginFailed());
Loading history...
1097
                }
1098
            }
1099
        }
1100
    }
1101
1102
    /**
1103
     * @return string
1104
     */
1105
    public function handleLoginFailed()
1106
    {
1107
        $message = get_lang('InvalidId');
1108
1109
        if (!isset($_GET['error'])) {
1110
            if (api_is_self_registration_allowed()) {
1111
                $message = get_lang('InvalidForSelfRegistration');
1112
            }
1113
        } else {
1114
            switch ($_GET['error']) {
1115
                case '':
1116
                    if (api_is_self_registration_allowed()) {
1117
                        $message = get_lang('InvalidForSelfRegistration');
1118
                    }
1119
                    break;
1120
                case 'account_expired':
1121
                    $message = get_lang('AccountExpired');
1122
                    break;
1123
                case 'account_inactive':
1124
                    $message = get_lang('AccountInactive');
1125
1126
                    if (api_get_setting('allow_registration') === 'confirmation') {
1127
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1128
                        $message .= Display::url(
1129
                            get_lang('ReSendConfirmationMail'),
1130
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1131
                            ['class' => 'alert-link']
1132
                        );
1133
                    }
1134
                    break;
1135
                case 'user_password_incorrect':
1136
                    $message = get_lang('InvalidId');
1137
                    break;
1138
                case 'access_url_inactive':
1139
                    $message = get_lang('AccountURLInactive');
1140
                    break;
1141
                case 'wrong_captcha':
1142
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1143
                    break;
1144
                case 'blocked_by_captcha':
1145
                    $message = get_lang('AccountBlockedByCaptcha');
1146
                    break;
1147
                case 'multiple_connection_not_allowed':
1148
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1149
                    break;
1150
                case 'unrecognize_sso_origin':
1151
                    //$message = get_lang('SSOError');
1152
                    break;
1153
            }
1154
        }
1155
1156
        return Display::return_message($message, 'error', false);
1157
    }
1158
1159
    public static function displayCASLoginButton($label = null)
1160
    {
1161
        $form = new FormValidator(
1162
            'form-cas-login',
1163
            'POST',
1164
            $_SERVER['REQUEST_URI'],
1165
            null,
1166
            null,
1167
            FormValidator::LAYOUT_BOX_NO_LABEL
1168
        );
1169
        $form->addHidden('forceCASAuthentication', 1);
1170
        $form->addButton(
1171
            'casLoginButton',
1172
            is_null($label) ? sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution")) : $label,
1173
            api_get_setting("casLogoURL"),
1174
            'primary',
1175
            null,
1176
            'btn-block'
1177
        );
1178
1179
        return $form->returnForm();
1180
    }
1181
1182
    public static function displayCASLogoutButton($label = null)
1183
    {
1184
        $form = new FormValidator(
1185
            'form-cas-logout',
1186
            'GET',
1187
            api_get_path(WEB_PATH),
1188
            null,
1189
            null,
1190
            FormValidator::LAYOUT_BOX_NO_LABEL
1191
        );
1192
        $form->addHidden('logout', 1);
1193
        $form->addButton(
1194
            'casLogoutButton',
1195
            is_null($label) ? sprintf(get_lang('LogoutWithYourAccountFromX'), api_get_setting("Institution")) : $label,
1196
            api_get_setting("casLogoURL"),
1197
            'primary',
1198
            null,
1199
            'btn-block'
1200
        );
1201
1202
        return $form->returnForm();
1203
    }
1204
1205
    /**
1206
     * @throws Exception
1207
     *
1208
     * @return string
1209
     */
1210
    public static function displayLoginForm()
1211
    {
1212
        // Get the $cas array from app/config/auth.conf.php
1213
        global $cas;
1214
1215
        if (is_array($cas) && array_key_exists('replace_login_form', $cas) && $cas['replace_login_form']) {
1216
            return self::displayCASLoginButton();
1217
        }
1218
1219
        $form = new FormValidator(
1220
            'formLogin',
1221
            'POST',
1222
            null,
1223
            null,
1224
            null,
1225
            FormValidator::LAYOUT_BOX_NO_LABEL
1226
        );
1227
        $params = [
1228
            'id' => 'login',
1229
            'autofocus' => 'autofocus',
1230
            'icon' => 'user fa-fw',
1231
            'placeholder' => get_lang('UserName'),
1232
        ];
1233
        if (api_get_configuration_value('security_login_autocomplete_disable') === true) {
1234
            $params['autocomplete'] = 'new-password';
1235
        }
1236
        $browserAutoCapitalize = false;
1237
        // Avoid showing the autocapitalize option if the browser doesn't
1238
        // support it: this attribute is against the HTML5 standard
1239
        if (api_browser_support('autocapitalize')) {
1240
            $browserAutoCapitalize = false;
1241
            $params['autocapitalize'] = 'none';
1242
        }
1243
        $form->addText(
1244
            'login',
1245
            get_lang('UserName'),
1246
            true,
1247
            $params
1248
        );
1249
        $params = [
1250
            'id' => 'password',
1251
            'icon' => 'lock fa-fw',
1252
            'placeholder' => get_lang('Pass'),
1253
        ];
1254
        if (api_get_configuration_value('security_login_autocomplete_disable') === true) {
1255
            $params['autocomplete'] = 'new-password';
1256
        }
1257
        if ($browserAutoCapitalize) {
1258
            $params['autocapitalize'] = 'none';
1259
        }
1260
        $form->addElement(
1261
            'password',
1262
            'password',
1263
            get_lang('Pass'),
1264
            $params
1265
        );
1266
        // Captcha
1267
        $captcha = api_get_setting('allow_captcha');
1268
        $allowCaptcha = $captcha === 'true';
1269
1270
        if ($allowCaptcha) {
1271
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1272
            if ($useCaptcha) {
1273
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1274
                $options = [
1275
                    'width' => 250,
1276
                    'height' => 90,
1277
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1278
                    'sessionVar' => basename(__FILE__, '.php'),
1279
                    'imageOptions' => [
1280
                        'font_size' => 20,
1281
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1282
                        'font_file' => 'OpenSans-Regular.ttf',
1283
                        //'output' => 'gif'
1284
                    ],
1285
                ];
1286
1287
                // Minimum options using all defaults (including defaults for Image_Text):
1288
                //$options = array('callback' => 'qfcaptcha_image.php');
1289
                $captchaQuestion = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1290
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1291
1292
                $form->addElement(
1293
                    'text',
1294
                    'captcha',
1295
                    get_lang('EnterTheLettersYouSee')
1296
                );
1297
                $form->addRule(
1298
                    'captcha',
1299
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1300
                    'required',
1301
                    null,
1302
                    'client'
1303
                );
1304
                $form->addRule(
1305
                    'captcha',
1306
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1307
                    'CAPTCHA',
1308
                    $captchaQuestion
1309
                );
1310
            }
1311
        }
1312
1313
        $form->addButton(
1314
            'submitAuth',
1315
            get_lang('LoginEnter'),
1316
            null,
1317
            'primary',
1318
            null,
1319
            'btn-block'
1320
        );
1321
1322
        $html = $form->returnForm();
1323
        if (api_get_setting('openid_authentication') == 'true') {
1324
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1325
            $html .= '<div>'.openid_form()->returnForm().'</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

1325
            $html .= '<div>'./** @scrutinizer ignore-call */ openid_form()->returnForm().'</div>';
Loading history...
1326
        }
1327
1328
        $pluginKeycloak = api_get_plugin_setting('keycloak', 'tool_enable') === 'true';
1329
        $plugin = null;
1330
        if ($pluginKeycloak) {
1331
            $pluginUrl = api_get_path(WEB_PLUGIN_PATH).'keycloak/start.php?sso';
1332
            $pluginUrl = Display::url('Keycloak', $pluginUrl, ['class' => 'btn btn-block btn-primary']);
1333
            $html .= '<div style="margin-top: 10px">'.$pluginUrl.'</div>';
1334
        }
1335
1336
        $html .= '<div></div>';
1337
1338
        return $html;
1339
    }
1340
1341
    public function enableCookieUsageWarning()
1342
    {
1343
        $form = new FormValidator(
1344
            'cookiewarning',
1345
            'post',
1346
            '',
1347
            '',
1348
            [
1349
                //'onsubmit' => "$(this).toggle('show')",
1350
            ],
1351
            FormValidator::LAYOUT_BOX_NO_LABEL
1352
        );
1353
        $form->addHidden('acceptCookies', '1');
1354
        $form->addHtml(
1355
            '<div class="cookieUsageValidation">
1356
                '.get_lang('YouAcceptCookies').'
1357
                <button class="btn btn-link" onclick="$(this).next().toggle(\'slow\'); $(this).toggle(\'slow\')" type="button">
1358
                    ('.get_lang('More').')
1359
                </button>
1360
                <div style="display:none; margin:20px 0;">
1361
                    '.get_lang('HelpCookieUsageValidation').'
1362
                </div>
1363
                <button class="btn btn-link" onclick="$(this).parents(\'form\').submit()" type="button">
1364
                    ('.get_lang('Accept').')
1365
                </button>
1366
            </div>'
1367
        );
1368
        $form->protect();
1369
1370
        if ($form->validate()) {
1371
            api_set_site_use_cookie_warning_cookie();
1372
        } else {
1373
            $this->assign('frmDisplayCookieUsageWarning', $form->returnForm());
1374
        }
1375
    }
1376
1377
    /**
1378
     * Returns the tutors names for the current course in session
1379
     * Function to use in Twig templates.
1380
     *
1381
     * @return string
1382
     */
1383
    public static function returnTutorsNames()
1384
    {
1385
        $em = Database::getManager();
1386
        $tutors = $em
1387
            ->createQuery('
1388
                SELECT u FROM ChamiloUserBundle:User u
1389
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1390
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1391
            ')
1392
            ->setParameters([
1393
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1394
                'session' => api_get_session_id(),
1395
                'course' => api_get_course_int_id(),
1396
            ])
1397
            ->getResult();
1398
1399
        $names = [];
1400
1401
        /** @var User $tutor */
1402
        foreach ($tutors as $tutor) {
1403
            $names[] = UserManager::formatUserFullName($tutor);
1404
        }
1405
1406
        return implode(CourseManager::USER_SEPARATOR, $names);
1407
    }
1408
1409
    /**
1410
     * Returns the teachers name for the current course
1411
     * Function to use in Twig templates.
1412
     *
1413
     * @return string
1414
     */
1415
    public static function returnTeachersNames()
1416
    {
1417
        $em = Database::getManager();
1418
        $teachers = $em
1419
            ->createQuery('
1420
                SELECT u FROM ChamiloUserBundle:User u
1421
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1422
                WHERE cu.status = :teacher_status AND cu.course = :course
1423
            ')
1424
            ->setParameters([
1425
                'teacher_status' => User::COURSE_MANAGER,
1426
                'course' => api_get_course_int_id(),
1427
            ])
1428
            ->getResult();
1429
1430
        $names = [];
1431
1432
        /** @var User $teacher */
1433
        foreach ($teachers as $teacher) {
1434
            $names[] = UserManager::formatUserFullName($teacher);
1435
        }
1436
1437
        return implode(CourseManager::USER_SEPARATOR, $names);
1438
    }
1439
1440
    /**
1441
     * @param int $code
1442
     */
1443
    public function setResponseCode($code)
1444
    {
1445
        $this->responseCode = $code;
1446
    }
1447
1448
    public function getResponseCode()
1449
    {
1450
        return $this->responseCode;
1451
    }
1452
1453
    /**
1454
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1455
     *
1456
     * @return bool Always return true because there is always a string, even if empty
1457
     */
1458
    public function assignBugNotification()
1459
    {
1460
        //@todo move this in the template
1461
        $rightFloatMenu = '';
1462
        $iconBug = Display::return_icon(
1463
            'bug.png',
1464
            get_lang('ReportABug'),
1465
            [],
1466
            ICON_SIZE_LARGE
1467
        );
1468
        if (api_get_setting('show_link_bug_notification') === 'true' && $this->user_is_logged_in) {
1469
            $rightFloatMenu = '<div class="report">
1470
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1471
                    '.$iconBug.'
1472
                </a>
1473
		        </div>';
1474
        }
1475
1476
        if (api_get_setting('show_link_ticket_notification') === 'true' &&
1477
            $this->user_is_logged_in
1478
        ) {
1479
            // by default is project_id = 1
1480
            $defaultProjectId = 1;
1481
            $iconTicket = Display::return_icon(
1482
                'help.png',
1483
                get_lang('Ticket'),
1484
                [],
1485
                ICON_SIZE_LARGE
1486
            );
1487
            $courseInfo = api_get_course_info();
1488
            $courseParams = '';
1489
            if (!empty($courseInfo)) {
1490
                $courseParams = api_get_cidreq();
1491
            }
1492
1493
            $extraParams = '';
1494
            if (api_get_configuration_value('ticket_lp_quiz_info_add')) {
1495
                if (isset($_GET['exerciseId']) && !empty($_GET['exerciseId'])) {
1496
                    $extraParams = '&exerciseId='.(int) $_GET['exerciseId'];
1497
                }
1498
1499
                if (isset($_GET['lp_id']) && !empty($_GET['lp_id'])) {
1500
                    $extraParams .= '&lpId='.(int) $_GET['lp_id'];
1501
                }
1502
            }
1503
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams.$extraParams;
1504
            $allow = TicketManager::userIsAllowInProject(api_get_user_info(), $defaultProjectId);
1505
1506
            if ($allow) {
1507
                $rightFloatMenu .= '<div class="help">
1508
                    <a href="'.$url.'" target="_blank">
1509
                        '.$iconTicket.'
1510
                    </a>
1511
                </div>';
1512
            }
1513
        }
1514
1515
        $this->assign('bug_notification', $rightFloatMenu);
1516
1517
        return true;
1518
    }
1519
1520
    /**
1521
     * Prepare the _c array for template files. The _c array contains
1522
     * information about the current course.
1523
     */
1524
    private function set_course_parameters()
1525
    {
1526
        //Setting course id
1527
        $course = api_get_course_info();
1528
        if (empty($course)) {
1529
            $this->assign('course_is_set', false);
1530
1531
            return;
1532
        }
1533
        $this->assign('course_is_set', true);
1534
        $this->course_id = $course['id'];
1535
        $_c = [
1536
            'id' => $course['real_id'],
1537
            'code' => $course['code'],
1538
            'title' => $course['name'],
1539
            'visibility' => $course['visibility'],
1540
            'language' => $course['language'],
1541
            'directory' => $course['directory'],
1542
            'session_id' => api_get_session_id(),
1543
            'user_is_teacher' => api_is_course_admin(),
1544
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
1545
        ];
1546
        $this->assign('course_code', $course['code']);
1547
        $this->assign('_c', $_c);
1548
    }
1549
1550
    /**
1551
     * Prepare the _u array for template files. The _u array contains
1552
     * information about the current user, as returned by
1553
     * api_get_user_info().
1554
     */
1555
    private function set_user_parameters()
1556
    {
1557
        $user_info = [];
1558
        $user_info['logged'] = 0;
1559
        $this->user_is_logged_in = false;
1560
        if (api_user_is_login()) {
1561
            $user_info = api_get_user_info(api_get_user_id(), true);
1562
            $user_info['logged'] = 1;
1563
1564
            $user_info['is_admin'] = 0;
1565
            if (api_is_platform_admin()) {
1566
                $user_info['is_admin'] = 1;
1567
            }
1568
1569
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1570
            $this->user_is_logged_in = true;
1571
        }
1572
        // Setting the $_u array that could be use in any template
1573
        $this->assign('_u', $user_info);
1574
    }
1575
1576
    /**
1577
     * Get an array of all the web paths available (e.g. 'web' => 'https://my.chamilo.site/').
1578
     *
1579
     * @return array
1580
     */
1581
    private function getWebPaths()
1582
    {
1583
        $queryString = empty($_SERVER['QUERY_STRING']) ? '' : $_SERVER['QUERY_STRING'];
1584
        $requestURI = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
1585
1586
        return [
1587
            'web' => api_get_path(WEB_PATH),
1588
            'web_url' => api_get_web_url(),
1589
            'web_relative' => api_get_path(REL_PATH),
1590
            'web_course' => api_get_path(WEB_COURSE_PATH),
1591
            'web_main' => api_get_path(WEB_CODE_PATH),
1592
            'web_css' => api_get_path(WEB_CSS_PATH),
1593
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
1594
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
1595
            'web_img' => api_get_path(WEB_IMG_PATH),
1596
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
1597
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
1598
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
1599
            'web_self' => api_get_self(),
1600
            'self_basename' => basename(api_get_self()),
1601
            'web_query_vars' => api_htmlentities($queryString),
1602
            'web_self_query_vars' => api_htmlentities($requestURI),
1603
            'web_cid_query' => api_get_cidreq(),
1604
            'web_rel_code' => api_get_path(REL_CODE_PATH),
1605
        ];
1606
    }
1607
1608
    /**
1609
     * Set header parameters.
1610
     *
1611
     * @param bool $sendHeaders send headers
1612
     */
1613
    private function set_header_parameters($sendHeaders)
1614
    {
1615
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1616
        $_course = api_get_course_info();
1617
        $nameTools = $this->title;
1618
        $navigation = return_navigation_array();
1619
        $this->menu_navigation = $navigation['menu_navigation'];
1620
1621
        $this->assign('system_charset', api_get_system_encoding());
1622
1623
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1624
            foreach ($httpHeadXtra as &$thisHttpHead) {
1625
                header($thisHttpHead);
1626
            }
1627
        }
1628
1629
        // Get language iso-code for this page - ignore errors
1630
        $this->assign('document_language', api_get_language_isocode());
1631
1632
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1633
1634
        $title_list = [];
1635
1636
        $title_list[] = api_get_setting('Institution');
1637
        $title_list[] = api_get_setting('siteName');
1638
1639
        if (!empty($course_title)) {
1640
            $title_list[] = $course_title;
1641
        }
1642
        if ($nameTools != '') {
1643
            $title_list[] = $nameTools;
1644
        }
1645
1646
        $title_string = '';
1647
        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...
1648
            $title_string .= $title_list[$i];
1649
            if (isset($title_list[$i + 1])) {
1650
                $item = trim($title_list[$i + 1]);
1651
                if (!empty($item)) {
1652
                    $title_string .= ' - ';
1653
                }
1654
            }
1655
        }
1656
1657
        $this->assign('title_string', $title_string);
1658
1659
        // Setting the theme and CSS files
1660
        $this->setCssFiles();
1661
        $this->set_js_files();
1662
        $this->setCssCustomFiles();
1663
1664
        $browser = api_browser_support('check_browser');
1665
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1666
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1667
            $this->assign('browser_specific_head', $browser_head);
1668
        }
1669
1670
        // Implementation of prefetch.
1671
        // See http://cdn.chamilo.org/main/img/online.png for details
1672
        $prefetch = '';
1673
        if (!empty($_configuration['cdn_enable'])) {
1674
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1675
            foreach ($_configuration['cdn'] as $host => $exts) {
1676
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1677
            }
1678
        }
1679
1680
        $this->assign('prefetch', $prefetch);
1681
        $this->assign('text_direction', api_get_text_direction());
1682
        $this->assign('section_name', 'section-'.$this_section);
1683
        $this->assignFavIcon();
1684
        $this->setHelp();
1685
1686
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1687
1688
        $this->assignAccessibilityBlock(); //Prepare the 'accessibility' var for the template
1689
1690
        // Preparing values for the menu
1691
1692
        // Logout link
1693
        $hideLogout = api_get_setting('hide_logout_button');
1694
        if ($hideLogout === 'true') {
1695
            $this->assign('logout_link', null);
1696
        } else {
1697
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1698
        }
1699
1700
        // Profile link
1701
        if (api_get_setting('allow_social_tool') == 'true') {
1702
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1703
        } else {
1704
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1705
        }
1706
1707
        $this->assign('profile_url', $profile_url);
1708
1709
        //Message link
1710
        $message_link = null;
1711
        $message_url = null;
1712
        if (api_get_setting('allow_message_tool') == 'true') {
1713
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1714
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1715
        }
1716
        $this->assign('message_link', $message_link);
1717
        $this->assign('message_url', $message_url);
1718
1719
        $pendingSurveyLink = '';
1720
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1721
        if ($show) {
1722
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1723
        }
1724
        $this->assign('pending_survey_url', $pendingSurveyLink);
1725
1726
        // Certificate Link
1727
        $allow = api_get_configuration_value('hide_my_certificate_link');
1728
        if ($allow === false) {
1729
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1730
            $certificateLink = Display::url(
1731
                get_lang('MyCertificates'),
1732
                $certificateUrl
1733
            );
1734
            $this->assign('certificate_link', $certificateLink);
1735
            $this->assign('certificate_url', $certificateUrl);
1736
        }
1737
1738
        $institution = api_get_setting('Institution');
1739
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1740
1741
        $this->assign('portal_name', $portal_name);
1742
1743
        //Menu
1744
        $menu = menuArray();
1745
        $this->assign('menu', $menu);
1746
1747
        $breadcrumb = '';
1748
        // Hide breadcrumb in LP
1749
        if ($this->show_learnpath == false) {
1750
            $breadcrumb = return_breadcrumb(
1751
                $interbreadcrumb,
1752
                $language_file,
1753
                $nameTools
1754
            );
1755
        }
1756
        $this->assign('breadcrumb', $breadcrumb);
1757
1758
        //Extra content
1759
        $extra_header = null;
1760
        if (!api_is_platform_admin()) {
1761
            $extra_header = trim(api_get_setting('header_extra_content'));
1762
        }
1763
        $this->assign('header_extra_content', $extra_header);
1764
1765
        if ($sendHeaders) {
1766
            header('Content-Type: text/html; charset='.api_get_system_encoding());
1767
            header(
1768
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1769
            );
1770
            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

1770
            self::/** @scrutinizer ignore-call */ 
1771
                  addHTTPSecurityHeaders();
Loading history...
1771
1772
            $responseCode = $this->getResponseCode();
1773
            if (!empty($responseCode)) {
1774
                switch ($responseCode) {
1775
                    case '404':
1776
                        header("HTTP/1.0 404 Not Found");
1777
                        break;
1778
                }
1779
            }
1780
        }
1781
1782
        $this->assignSocialMeta();
1783
    }
1784
1785
    /**
1786
     * Set footer parameters.
1787
     */
1788
    private function set_footer_parameters()
1789
    {
1790
        if (api_get_setting('show_administrator_data') === 'true') {
1791
            $firstName = api_get_setting('administratorName');
1792
            $lastName = api_get_setting('administratorSurname');
1793
1794
            if (!empty($firstName) && !empty($lastName)) {
1795
                $name = api_get_person_name($firstName, $lastName);
1796
            } else {
1797
                $name = $lastName;
1798
                if (empty($lastName)) {
1799
                    $name = $firstName;
1800
                }
1801
            }
1802
1803
            $adminName = '';
1804
            // Administrator name
1805
            if (!empty($name)) {
1806
                $adminName = get_lang('Manager').' : ';
1807
                $adminName .= Display::encrypted_mailto_link(
1808
                    api_get_setting('emailAdministrator'),
1809
                    $name,
1810
                    '',
1811
                    true
1812
                );
1813
            }
1814
            $this->assign('administrator_name', $adminName);
1815
        }
1816
1817
        // Loading footer extra content
1818
        if (!api_is_platform_admin()) {
1819
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1820
            if (!empty($extra_footer)) {
1821
                $this->assign('footer_extra_content', $extra_footer);
1822
            }
1823
        }
1824
1825
        // Tutor name
1826
        if (api_get_setting('show_tutor_data') == 'true') {
1827
            // Course manager
1828
            $courseId = api_get_course_int_id();
1829
            $id_session = api_get_session_id();
1830
            if (!empty($courseId)) {
1831
                $tutor_data = '';
1832
                if ($id_session != 0) {
1833
                    $users = SessionManager::getCoachesByCourseSession($id_session, $courseId);
1834
                    $links = [];
1835
                    if (!empty($users)) {
1836
                        $coaches = [];
1837
                        foreach ($users as $userId) {
1838
                            $coaches[] = api_get_user_info($userId);
1839
                        }
1840
                        $links = array_column($coaches, 'complete_name_with_message_link');
1841
                    }
1842
                    $count = count($links);
1843
                    if ($count > 1) {
1844
                        $tutor_data .= get_lang('Coachs').' : ';
1845
                        $tutor_data .= array_to_string($links, CourseManager::USER_SEPARATOR);
1846
                    } elseif ($count === 1) {
1847
                        $tutor_data .= get_lang('Coach').' : ';
1848
                        $tutor_data .= array_to_string($links, CourseManager::USER_SEPARATOR);
1849
                    } elseif ($count === 0) {
1850
                        $tutor_data .= '';
1851
                    }
1852
                }
1853
                $this->assign('session_teachers', $tutor_data);
1854
            }
1855
        }
1856
1857
        if (api_get_setting('show_teacher_data') == 'true') {
1858
            // course manager
1859
            $courseId = api_get_course_int_id();
1860
            if (!empty($courseId)) {
1861
                $teacher_data = '';
1862
                $teachers = CourseManager::getTeachersFromCourse($courseId);
1863
                if (!empty($teachers)) {
1864
                    $teachersParsed = [];
1865
                    foreach ($teachers as $teacher) {
1866
                        $userId = $teacher['id'];
1867
                        $teachersParsed[] = api_get_user_info($userId);
1868
                    }
1869
                    $links = array_column($teachersParsed, 'complete_name_with_message_link');
1870
                    $label = get_lang('Teacher');
1871
                    if (count($links) > 1) {
1872
                        $label = get_lang('Teachers');
1873
                    }
1874
                    $teacher_data .= $label.' : '.array_to_string($links, CourseManager::USER_SEPARATOR);
1875
                }
1876
                $this->assign('teachers', $teacher_data);
1877
            }
1878
        }
1879
    }
1880
1881
    /**
1882
     * Set administrator variables.
1883
     */
1884
    private function setAdministratorParams()
1885
    {
1886
        $_admin = [
1887
            'email' => api_get_setting('emailAdministrator'),
1888
            'surname' => api_get_setting('administratorSurname'),
1889
            'name' => api_get_setting('administratorName'),
1890
            'telephone' => api_get_setting('administratorTelephone'),
1891
        ];
1892
1893
        $this->assign('_admin', $_admin);
1894
    }
1895
1896
    /**
1897
     * Manage specific HTTP headers security.
1898
     */
1899
    private function addHTTPSecurityHeaders()
1900
    {
1901
        // Implementation of HTTP headers security, as suggested and checked
1902
        // by https://securityheaders.io/
1903
        // Enable these settings in configuration.php to use them on your site
1904
        // Strict-Transport-Security
1905
        $setting = api_get_configuration_value('security_strict_transport');
1906
        if (!empty($setting)) {
1907
            header('Strict-Transport-Security: '.$setting);
1908
        }
1909
        // Content-Security-Policy
1910
        $setting = api_get_configuration_value('security_content_policy');
1911
        if (!empty($setting)) {
1912
            header('Content-Security-Policy: '.$setting);
1913
        }
1914
        $setting = api_get_configuration_value('security_content_policy_report_only');
1915
        if (!empty($setting)) {
1916
            header('Content-Security-Policy-Report-Only: '.$setting);
1917
        }
1918
        // Public-Key-Pins
1919
        $setting = api_get_configuration_value('security_public_key_pins');
1920
        if (!empty($setting)) {
1921
            header('Public-Key-Pins: '.$setting);
1922
        }
1923
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1924
        if (!empty($setting)) {
1925
            header('Public-Key-Pins-Report-Only: '.$setting);
1926
        }
1927
        // X-Frame-Options
1928
        $setting = api_get_configuration_value('security_x_frame_options');
1929
        if (!empty($setting)) {
1930
            header('X-Frame-Options: '.$setting);
1931
        }
1932
        // X-XSS-Protection
1933
        $setting = api_get_configuration_value('security_xss_protection');
1934
        if (!empty($setting)) {
1935
            header('X-XSS-Protection: '.$setting);
1936
        }
1937
        // X-Content-Type-Options
1938
        $setting = api_get_configuration_value('security_x_content_type_options');
1939
        if (!empty($setting)) {
1940
            header('X-Content-Type-Options: '.$setting);
1941
        }
1942
        // Referrer-Policy
1943
        $setting = api_get_configuration_value('security_referrer_policy');
1944
        if (!empty($setting)) {
1945
            header('Referrer-Policy: '.$setting);
1946
        }
1947
        // Permissions-Policy
1948
        $setting = api_get_configuration_value('security_permissions_policy');
1949
        if (!empty($setting)) {
1950
            header('Permissions-Policy: '.$setting);
1951
        }
1952
        // end of HTTP headers security block
1953
    }
1954
1955
    /**
1956
     * Assign favicon to the 'favico' template variable.
1957
     *
1958
     * @return bool Always return true because there is always at least one correct favicon.ico
1959
     */
1960
    private function assignFavIcon()
1961
    {
1962
        // Default root chamilo favicon
1963
        $favico = '<link rel="icon" href="'.api_get_path(WEB_PATH).'favicon.png" type="image/png" />';
1964
1965
        //Added to verify if in the current Chamilo Theme exist a favicon
1966
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1967
1968
        //If exist pick the current chamilo theme favicon
1969
        if (is_file($favicoThemeUrl.'favicon.png')) {
1970
            $favico = '<link rel="icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.png" type="image/png" />';
1971
        }
1972
1973
        if (api_is_multiple_url_enabled()) {
1974
            $access_url_id = api_get_current_access_url_id();
1975
            if ($access_url_id != -1) {
1976
                $url_info = api_get_access_url($access_url_id);
1977
                $url = api_remove_trailing_slash(
1978
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1979
                );
1980
                $clean_url = api_replace_dangerous_char($url);
1981
                $clean_url = str_replace('/', '-', $clean_url);
1982
                $clean_url .= '/';
1983
                $homep = api_get_path(WEB_HOME_PATH).$clean_url; //homep for Home Path
1984
                $icon_real_homep = api_get_path(SYS_HOME_PATH).$clean_url;
1985
                //we create the new dir for the new sites
1986
                if (is_file($icon_real_homep.'favicon.ico')) {
1987
                    $favico = '<link rel="icon" href="'.$homep.'favicon.png" type="image/png" />';
1988
                }
1989
            }
1990
        }
1991
1992
        $this->assign('favico', $favico);
1993
1994
        return true;
1995
    }
1996
1997
    /**
1998
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1999
     *
2000
     * @return bool Always return true (even if empty string)
2001
     */
2002
    private function assignAccessibilityBlock()
2003
    {
2004
        $resize = '';
2005
        if (api_get_setting('accessibility_font_resize') == 'true') {
2006
            $resize .= '<div class="resize_font">';
2007
            $resize .= '<div class="btn-group">';
2008
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
2009
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
2010
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
2011
            $resize .= '</div>';
2012
            $resize .= '</div>';
2013
        }
2014
        $this->assign('accessibility', $resize);
2015
2016
        return true;
2017
    }
2018
2019
    /**
2020
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
2021
     *
2022
     * @return bool Always return true (even if empty string)
2023
     */
2024
    private function assignSocialMeta()
2025
    {
2026
        $socialMeta = '';
2027
        $metaTitle = api_get_setting('meta_title');
2028
        if (!empty($metaTitle)) {
2029
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
2030
            $metaSite = api_get_setting('meta_twitter_site');
2031
            if (!empty($metaSite)) {
2032
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
2033
                $metaCreator = api_get_setting('meta_twitter_creator');
2034
                if (!empty($metaCreator)) {
2035
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
2036
                }
2037
            }
2038
2039
            // The user badge page emits its own meta tags, so if this is
2040
            // enabled, ignore the global ones
2041
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
2042
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
2043
2044
            if (!$userId && !$skillId) {
2045
                // no combination of user and skill ID has been defined,
2046
                // so print the normal or course-specific OpenGraph meta tags
2047
                // Check for a course ID
2048
                $courseId = api_get_course_int_id();
2049
                // Check session ID from session/id/about (see .htaccess)
2050
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
2051
2052
                if ($courseId != false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $courseId of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
2053
                    // If we are inside a course (even if within a session), publish info about the course
2054
                    $course = api_get_course_entity($courseId);
2055
                    // @TODO: support right-to-left in title
2056
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
2057
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
2058
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
2059
2060
                    $metaDescription = api_get_setting('meta_description');
2061
                    if (!empty($course->getDescription())) {
2062
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
2063
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
2064
                    } elseif (!empty($metaDescription)) {
2065
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
2066
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
2067
                    }
2068
2069
                    $picture = CourseManager::getPicturePath($course, true);
2070
                    if (!empty($picture)) {
2071
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
2072
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
2073
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
2074
                    } else {
2075
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
2076
                    }
2077
                } elseif ($sessionId !== 0) {
2078
                    // If we are on a session "about" screen, publish info about the session
2079
                    $em = Database::getManager();
2080
                    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
2081
2082
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
2083
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
2084
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."session/{$session->getId()}/about/".'" />'."\n";
2085
2086
                    $sessionValues = new ExtraFieldValue('session');
2087
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
2088
                    $sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
2089
2090
                    if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
2091
                        $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
2092
                        $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
2093
                        $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
2094
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
2095
                    } else {
2096
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
2097
                    }
2098
                } else {
2099
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
2100
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
2101
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
2102
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
2103
2104
                    $metaDescription = api_get_setting('meta_description');
2105
                    if (!empty($metaDescription)) {
2106
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
2107
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
2108
                    }
2109
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
2110
                }
2111
            }
2112
        }
2113
2114
        $this->assign('social_meta', $socialMeta);
2115
2116
        return true;
2117
    }
2118
2119
    /**
2120
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
2121
     *
2122
     * @param string $imageAlt The alt attribute for the image
2123
     *
2124
     * @return string The meta image HTML tag, or empty
2125
     */
2126
    private function getMetaPortalImagePath($imageAlt = '')
2127
    {
2128
        // Load portal meta image if defined
2129
        $metaImage = api_get_setting('meta_image_path');
2130
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
2131
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
2132
        $portalImageMeta = '';
2133
        if (!empty($metaImage)) {
2134
            if (is_file($metaImageSysPath)) {
2135
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
2136
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
2137
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
2138
            }
2139
        } else {
2140
            if (api_get_configuration_value('mail_header_from_custom_course_logo') == true) {
2141
                // check if current page is a course page
2142
                $courseId = api_get_course_int_id();
2143
2144
                if (!empty($courseId)) {
2145
                    $course = api_get_course_info_by_id($courseId);
2146
                    if (!empty($course) && !empty($course['course_email_image_large'])) {
2147
                        $portalImageMeta = '<meta property="og:image" content="'.$course['course_email_image_large'].'" />'."\n";
2148
                        $portalImageMeta .= '<meta property="twitter:image" content="'.$course['course_email_image_large'].'" />'."\n";
2149
                        $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
2150
                    }
2151
                }
2152
            }
2153
            if (empty($portalImageMeta)) {
2154
                $logo = ChamiloApi::getPlatformLogoPath($this->theme);
2155
                if (!empty($logo)) {
2156
                    $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
2157
                    $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
2158
                    $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
2159
                }
2160
            }
2161
        }
2162
2163
        return $portalImageMeta;
2164
    }
2165
}
2166