Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/inc/lib/template.lib.php (1 issue)

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
        ];
204
205
        foreach ($functions as $function) {
206
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
207
        }
208
209
        // Setting system variables
210
        $this->set_system_parameters();
211
212
        // Setting user variables
213
        $this->set_user_parameters();
214
215
        // Setting course variables
216
        $this->set_course_parameters();
217
218
        // Setting administrator variables
219
        $this->setAdministratorParams();
220
        //$this->setCSSEditor();
221
222
        // Header and footer are showed by default
223
        $this->set_footer($show_footer);
224
        $this->set_header($show_header);
225
226
        $this->set_header_parameters($sendHeaders);
227
        $this->set_footer_parameters();
228
229
        $defaultStyle = api_get_configuration_value('default_template');
230
        if (!empty($defaultStyle)) {
231
            $this->templateFolder = $defaultStyle;
232
        }
233
234
        $this->assign('template', $this->templateFolder);
235
        $this->assign('locale', api_get_language_isocode());
236
        $this->assign('login_class', null);
237
238
        $allow = api_get_configuration_value('show_language_selector_in_menu');
239
        if ($allow) {
240
            $this->assign('language_form', api_display_language_form());
241
        }
242
243
        if (api_get_configuration_value('notification_event')) {
244
            $this->assign('notification_event', '1');
245
        }
246
247
        // Chamilo plugins
248
        if ($this->show_header) {
249
            if ($this->load_plugins) {
250
                $this->plugin = new AppPlugin();
251
252
                //1. Showing installed plugins in regions
253
                $pluginRegions = $this->plugin->get_plugin_regions();
254
                foreach ($pluginRegions as $region) {
255
                    $this->set_plugin_region($region);
256
                }
257
258
                //2. Loading the course plugin info
259
                global $course_plugin;
260
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
261
                    //Load plugin get_langs
262
                    $this->plugin->load_plugin_lang_variables($course_plugin);
263
                }
264
            }
265
        }
266
    }
267
268
    /**
269
     * Return the item's url key:.
270
     *
271
     *      c_id=xx&id=xx
272
     *
273
     * @param object $item
274
     *
275
     * @return string
276
     */
277
    public static function key($item)
278
    {
279
        $id = isset($item->id) ? $item->id : null;
280
        $c_id = isset($item->c_id) ? $item->c_id : null;
281
        $result = '';
282
        if ($c_id) {
283
            $result = "c_id=$c_id";
284
        }
285
        if ($id) {
286
            if ($result) {
287
                $result .= "&amp;id=$id";
288
            } else {
289
                $result .= "&amp;id=$id";
290
            }
291
        }
292
293
        return $result;
294
    }
295
296
    /**
297
     * @param string $helpInput
298
     */
299
    public function setHelp($helpInput = null)
300
    {
301
        if (!empty($helpInput)) {
302
            $help = $helpInput;
303
        } else {
304
            $help = $this->help;
305
        }
306
307
        $content = '';
308
        if (api_get_setting('enable_help_link') == 'true') {
309
            if (!empty($help)) {
310
                $help = Security::remove_XSS($help);
311
                $content = '<div class="help">';
312
                $content .= Display::url(
313
                    Display::return_icon('help.large.png', get_lang('Help')),
314
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
315
                    [
316
                        'class' => 'ajax',
317
                        'data-title' => get_lang('Help'),
318
                    ]
319
                );
320
                $content .= '</div>';
321
            }
322
        }
323
        $this->assign('help_content', $content);
324
    }
325
326
    /**
327
     * Use template system to parse the actions menu.
328
     *
329
     * @todo finish it!
330
     */
331
    public function set_actions($actions)
332
    {
333
        $action_string = '';
334
        if (!empty($actions)) {
335
            foreach ($actions as $action) {
336
                $action_string .= $action;
337
            }
338
        }
339
        $this->assign('actions', $actions);
340
    }
341
342
    /**
343
     * Shortcut to display a 1 col layout (index.php).
344
     * */
345
    public function display_one_col_template()
346
    {
347
        $tpl = $this->get_template('layout/layout_1_col.tpl');
348
        $this->display($tpl);
349
    }
350
351
    /**
352
     * Shortcut to display a 2 col layout (userportal.php).
353
     */
354
    public function display_two_col_template()
355
    {
356
        $tpl = $this->get_template('layout/layout_2_col.tpl');
357
        $this->display($tpl);
358
    }
359
360
    /**
361
     * Displays an empty template.
362
     */
363
    public function display_blank_template()
364
    {
365
        $tpl = $this->get_template('layout/blank.tpl');
366
        $this->display($tpl);
367
    }
368
369
    /**
370
     * Displays an empty template.
371
     */
372
    public function displayBlankTemplateNoHeader()
373
    {
374
        $tpl = $this->get_template('layout/blank_no_header.tpl');
375
        $this->display($tpl);
376
    }
377
378
    /**
379
     * Displays an empty template.
380
     */
381
    public function display_no_layout_template()
382
    {
383
        $tpl = $this->get_template('layout/no_layout.tpl');
384
        $this->display($tpl);
385
    }
386
387
    /**
388
     * Sets the footer visibility.
389
     *
390
     * @param bool true if we show the footer
391
     */
392
    public function set_footer($status)
393
    {
394
        $this->show_footer = $status;
395
        $this->assign('show_footer', $status);
396
    }
397
398
    /**
399
     * return true if toolbar has to be displayed for user.
400
     *
401
     * @return bool
402
     */
403
    public static function isToolBarDisplayedForUser()
404
    {
405
        //Toolbar
406
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
407
        $show_toolbar = false;
408
409
        switch ($show_admin_toolbar) {
410
            case 'do_not_show':
411
                break;
412
            case 'show_to_admin':
413
                if (api_is_platform_admin()) {
414
                    $show_toolbar = true;
415
                }
416
                break;
417
            case 'show_to_admin_and_teachers':
418
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
419
                    $show_toolbar = true;
420
                }
421
                break;
422
            case 'show_to_all':
423
                $show_toolbar = true;
424
                break;
425
        }
426
427
        return $show_toolbar;
428
    }
429
430
    /**
431
     * Sets the header visibility.
432
     *
433
     * @param bool true if we show the header
434
     */
435
    public function set_header($status)
436
    {
437
        $this->show_header = $status;
438
        $this->assign('show_header', $status);
439
440
        $show_toolbar = 0;
441
442
        if (self::isToolBarDisplayedForUser()) {
443
            $show_toolbar = 1;
444
        }
445
446
        $this->assign('show_toolbar', $show_toolbar);
447
448
        // Only if course is available
449
        $courseToolBar = '';
450
        $origin = api_get_origin();
451
        $show_course_navigation_menu = '';
452
        if (!empty($this->course_id) && $this->user_is_logged_in) {
453
            if ($origin !== 'embeddable' && api_get_setting('show_toolshortcuts') !== 'false') {
454
                // Course toolbar
455
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
456
            }
457
            if (api_get_setting('show_navigation_menu') != 'false') {
458
                // Course toolbar
459
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
460
            }
461
        }
462
        $this->assign('show_course_shortcut', $courseToolBar);
463
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
464
    }
465
466
    /**
467
     * Returns the sub-folder and filename for the given tpl file.
468
     *
469
     * If template not found in overrides/ or custom template folder, the default template will be used.
470
     *
471
     * @param string $name
472
     *
473
     * @return string
474
     */
475
    public static function findTemplateFilePath($name)
476
    {
477
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
478
479
        // Check if the tpl file is present in the main/template/overrides/ dir
480
        // Overrides is a special directory meant for temporary template
481
        // customization. It must be taken into account before anything else
482
        if (is_readable($sysTemplatePath."overrides/$name")) {
483
            return "overrides/$name";
484
        }
485
486
        $defaultFolder = api_get_configuration_value('default_template');
487
488
        // If a template folder has been manually defined, search for the right
489
        // file, and if not found, go for the same file in the default template
490
        if ($defaultFolder && $defaultFolder != 'default') {
491
            // Avoid missing template error, use the default file.
492
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
493
                return "$defaultFolder/$name";
494
            }
495
        }
496
497
        return "default/$name";
498
    }
499
500
    /**
501
     * Call non-static for Template::findTemplateFilePath.
502
     *
503
     * @see Template::findTemplateFilePath()
504
     *
505
     * @param string $name
506
     *
507
     * @return string
508
     */
509
    public function get_template($name)
510
    {
511
        return api_find_template($name);
512
    }
513
514
    /**
515
     * Get CSS themes sub-directory.
516
     *
517
     * @param string $theme
518
     *
519
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
520
     */
521
    public static function getThemeDir($theme)
522
    {
523
        $themeDir = 'themes/'.$theme.'/';
524
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
525
        if (!empty($virtualTheme)) {
526
            $virtualThemeList = api_get_themes(true);
527
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
528
            if ($isVirtualTheme) {
529
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
530
            }
531
        }
532
533
        return $themeDir;
534
    }
535
536
    /**
537
     * Set system parameters from api_get_configuration into _s array for use in TPLs
538
     * Also fills the _p array from getWebPaths().
539
     *
540
     * @uses \self::getWebPaths()
541
     */
542
    public function set_system_parameters()
543
    {
544
        // Get the interface language from global.inc.php
545
        global $language_interface;
546
        $this->theme = api_get_visual_theme();
547
        if (!empty($this->preview_theme)) {
548
            $this->theme = $this->preview_theme;
549
        }
550
551
        $this->themeDir = self::getThemeDir($this->theme);
552
553
        // Setting app paths/URLs
554
        $this->assign('_p', $this->getWebPaths());
555
556
        // Here we can add system parameters that can be use in any template
557
        $_s = [
558
            'software_name' => api_get_configuration_value('software_name'),
559
            'system_version' => api_get_configuration_value('system_version'),
560
            'site_name' => api_get_setting('siteName'),
561
            'institution' => api_get_setting('Institution'),
562
            'institution_url' => api_get_setting('InstitutionUrl'),
563
            'date' => api_format_date('now', DATE_FORMAT_LONG),
564
            'timezone' => api_get_timezone(),
565
            'gamification_mode' => api_get_setting('gamification_mode'),
566
            'language_interface' => $language_interface,
567
        ];
568
        $this->assign('_s', $_s);
569
    }
570
571
    /**
572
     * Set theme, include mainstream CSS files.
573
     *
574
     * @see setCssCustomFiles() for additional CSS sheets
575
     */
576
    public function setCssFiles()
577
    {
578
        global $disable_js_and_css_files;
579
        $css = [];
580
581
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
582
        $webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
583
584
        // Default CSS Bootstrap
585
        $bowerCSSFiles = [
586
            'fontawesome/css/font-awesome.min.css',
587
            'jquery-ui/themes/smoothness/theme.css',
588
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
589
            'mediaelement/build/mediaelementplayer.min.css',
590
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
591
            'bootstrap/dist/css/bootstrap.min.css',
592
            'jquery.scrollbar/jquery.scrollbar.css',
593
            'bootstrap-daterangepicker/daterangepicker.css',
594
            'bootstrap-select/dist/css/bootstrap-select.min.css',
595
            'select2/dist/css/select2.min.css',
596
        ];
597
598
        $hide = api_get_configuration_value('hide_flag_language_switcher');
599
600
        if ($hide === false) {
601
            $bowerCSSFiles[] = 'flag-icon-css/css/flag-icon.min.css';
602
        }
603
604
        foreach ($bowerCSSFiles as $file) {
605
            $css[] = api_get_cdn_path($webPublicPath.'assets/'.$file);
606
        }
607
608
        $css[] = $webJsPath.'mediaelement/plugins/vrview/vrview.css';
609
610
        $features = api_get_configuration_value('video_features');
611
        $defaultFeatures = [
612
            'playpause',
613
            'current',
614
            'progress',
615
            'duration',
616
            'tracks',
617
            'volume',
618
            'fullscreen',
619
            'vrview',
620
            'markersrolls',
621
        ];
622
623
        if (!empty($features) && isset($features['features'])) {
624
            foreach ($features['features'] as $feature) {
625
                if ($feature === 'vrview') {
626
                    continue;
627
                }
628
                $css[] = $webJsPath."mediaelement/plugins/$feature/$feature.min.css";
629
                $defaultFeatures[] = $feature;
630
            }
631
        }
632
633
        $css[] = $webJsPath.'chosen/chosen.css';
634
635
        if (api_is_global_chat_enabled()) {
636
            $css[] = $webJsPath.'chat/css/chat.css';
637
        }
638
        $css_file_to_string = '';
639
        foreach ($css as $file) {
640
            $css_file_to_string .= api_get_css($file);
641
        }
642
643
        if (!$disable_js_and_css_files) {
644
            $this->assign('css_static_file_to_string', $css_file_to_string);
645
        }
646
647
        $defaultFeatures = implode("','", $defaultFeatures);
648
        $this->assign('video_features', $defaultFeatures);
649
    }
650
651
    /**
652
     * Prepare custom CSS to be added at the very end of the <head> section.
653
     *
654
     * @see setCssFiles() for the mainstream CSS files
655
     */
656
    public function setCssCustomFiles()
657
    {
658
        global $disable_js_and_css_files;
659
        // Base CSS
660
        $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...
661
662
        if ($this->show_learnpath) {
663
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
664
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
665
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
666
            }
667
        }
668
        if (CustomPages::enabled()) {
669
            $cssCustomPage = api_get_path(SYS_CSS_PATH).$this->themeDir."custompage.css";
670
            if (is_file($cssCustomPage)) {
671
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'custompage.css';
672
            } else {
673
                $css[] = api_get_path(WEB_CSS_PATH).'custompage.css';
674
            }
675
        }
676
677
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
678
        $css[] = api_get_cdn_path(ChamiloApi::getEditorBlockStylePath());
679
680
        $css_file_to_string = null;
681
        foreach ($css as $file) {
682
            $css_file_to_string .= api_get_css($file);
683
        }
684
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
685
        if (SHOW_TEXT_NEAR_ICONS == true) {
686
            //hack in order to fix the actions buttons
687
            $css_file_to_string .= '<style>
688
                .td_actions a {
689
                    float:left;
690
                    width:100%;
691
                }
692
                .forum_message_left a {
693
                    float:left;
694
                    width:100%;
695
                }
696
                </style>';
697
        }
698
699
        $navigator_info = api_get_navigator();
700
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
701
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
702
        }
703
704
        if (!$disable_js_and_css_files) {
705
            $this->assign('css_custom_file_to_string', $css_file_to_string);
706
707
            $style_print = api_get_css(
708
                api_get_print_css(false, true),
709
                'print'
710
            );
711
            $this->assign('css_style_print', $style_print);
712
        }
713
714
        // Logo
715
        $logo = return_logo($this->theme);
716
        $logoPdf = return_logo($this->theme, false);
717
        $this->assign('logo', $logo);
718
        $this->assign('logo_pdf', $logoPdf);
719
        $this->assign('show_media_element', 1);
720
    }
721
722
    /**
723
     * Declare and define the template variable that will be used to load
724
     * javascript libraries in the header.
725
     */
726
    public function set_js_files()
727
    {
728
        global $disable_js_and_css_files, $htmlHeadXtra;
729
        $isoCode = api_get_language_isocode();
730
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
731
732
        if ($isoCode == 'en') {
733
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
734
        }
735
        // JS files
736
        $js_files = [
737
            'chosen/chosen.jquery.min.js',
738
            'mediaelement/plugins/vrview/vrview.js',
739
            'mediaelement/plugins/markersrolls/markersrolls.min.js',
740
        ];
741
742
        if (api_get_setting('accessibility_font_resize') === 'true') {
743
            $js_files[] = 'fontresize.js';
744
        }
745
746
        $js_file_to_string = '';
747
        $bowerJsFiles = [
748
            'modernizr/modernizr.js',
749
            'jquery/dist/jquery.min.js',
750
            'bootstrap/dist/js/bootstrap.min.js',
751
            'jquery-ui/jquery-ui.min.js',
752
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
753
            'moment/min/moment-with-locales.js',
754
            'bootstrap-daterangepicker/daterangepicker.js',
755
            'jquery-timeago/jquery.timeago.js',
756
            'mediaelement/build/mediaelement-and-player.min.js',
757
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
758
            'image-map-resizer/js/imageMapResizer.min.js',
759
            'jquery.scrollbar/jquery.scrollbar.min.js',
760
            'readmore-js/readmore.min.js',
761
            'bootstrap-select/dist/js/bootstrap-select.min.js',
762
            $selectLink,
763
            'select2/dist/js/select2.min.js',
764
            "select2/dist/js/i18n/$isoCode.js",
765
            'js-cookie/src/js.cookie.js',
766
        ];
767
768
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
769
770
        if ($viewBySession || api_is_global_chat_enabled()) {
771
            // Do not include the global chat in LP
772
            if ($this->show_learnpath == false &&
773
                $this->show_footer == true &&
774
                $this->hide_global_chat == false
775
            ) {
776
                $js_files[] = 'chat/js/chat.js';
777
                $bowerJsFiles[] = 'linkifyjs/linkify.js';
778
                $bowerJsFiles[] = 'linkifyjs/linkify-jquery.js';
779
            }
780
        }
781
782
        $features = api_get_configuration_value('video_features');
783
        if (!empty($features) && isset($features['features'])) {
784
            foreach ($features['features'] as $feature) {
785
                if ($feature === 'vrview') {
786
                    continue;
787
                }
788
                $js_files[] = "mediaelement/plugins/$feature/$feature.min.js";
789
            }
790
        }
791
792
        if (CHAMILO_LOAD_WYSIWYG === true) {
793
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
794
        }
795
796
        if (api_get_setting('include_asciimathml_script') === 'true') {
797
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
798
        }
799
800
        // If not English and the language is supported by timepicker, localize
801
        $assetsPath = api_get_path(SYS_PUBLIC_PATH).'assets/';
802
        if ($isoCode != 'en') {
803
            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')) {
804
                $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
805
                $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
806
            }
807
        }
808
809
        foreach ($bowerJsFiles as $file) {
810
            $js_file_to_string .= '<script src="'.api_get_cdn_path(api_get_path(WEB_PUBLIC_PATH).'assets/'.$file).'"></script>'."\n";
811
        }
812
813
        foreach ($js_files as $file) {
814
            $js_file_to_string .= api_get_js($file);
815
        }
816
817
        // Loading email_editor js
818
        if (api_get_setting('allow_email_editor') === 'true') {
819
            $link = 'email_editor.php';
820
            if (!api_is_anonymous()) {
821
                $this->assign('email_editor', $link);
822
                $template = $this->get_template('mail_editor/email_link.js.tpl');
823
                $js_file_to_string .= $this->fetch($template);
824
            } else {
825
                if (api_get_configuration_value('allow_email_editor_for_anonymous')) {
826
                    $link = 'email_editor_external.php';
827
                    $this->assign('email_editor', $link);
828
                    $template = $this->get_template('mail_editor/email_link.js.tpl');
829
                    $js_file_to_string .= $this->fetch($template);
830
                }
831
            }
832
        }
833
834
        if (!$disable_js_and_css_files) {
835
            $this->assign('js_file_to_string', $js_file_to_string);
836
837
            $extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
838
            // Adding jquery ui by default
839
            $extraHeaders .= api_get_jquery_ui_js();
840
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
841
                foreach ($htmlHeadXtra as &$this_html_head) {
842
                    $extraHeaders .= $this_html_head."\n";
843
                }
844
            }
845
846
            $ajax = api_get_path(WEB_AJAX_PATH);
847
            $courseId = api_get_course_id();
848
            if (empty($courseId)) {
849
                $courseLogoutCode = '
850
                <script>
851
                function courseLogout() {
852
                }
853
                </script>';
854
            } else {
855
                $courseLogoutCode = "
856
                <script>
857
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
858
                function courseLogout() {
859
                    $.ajax({
860
                        async : false,
861
                        url: logOutUrl,
862
                        success: function (data) {
863
                            return 1;
864
                        }
865
                    });
866
                }
867
                </script>";
868
            }
869
870
            $extraHeaders .= $courseLogoutCode;
871
            $this->assign('extra_headers', $extraHeaders);
872
        }
873
    }
874
875
    /**
876
     * Special function to declare last-minute JS libraries which depend on
877
     * other things to be declared first. In particular, it might be useful
878
     * under IE9 with compatibility mode, which for some reason is getting
879
     * upset when a variable is used in a function (even if not used yet)
880
     * when this variable hasn't been defined yet.
881
     */
882
    public function set_js_files_post()
883
    {
884
        global $disable_js_and_css_files;
885
        $js_files = [];
886
        $bower = '';
887
        if (api_is_global_chat_enabled()) {
888
            //Do not include the global chat in LP
889
            if ($this->show_learnpath == false && $this->show_footer == true && $this->hide_global_chat == false) {
890
                $js_files[] = 'chat/js/chat.js';
891
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify.js"></script>';
892
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify-jquery.js"></script>';
893
            }
894
        }
895
        $js_file_to_string = '';
896
        foreach ($js_files as $js_file) {
897
            $js_file_to_string .= api_get_js($js_file);
898
        }
899
        if (!$disable_js_and_css_files) {
900
            $this->assign('js_file_to_string_post', $js_file_to_string.$bower);
901
        }
902
    }
903
904
    /**
905
     * Show header template.
906
     */
907
    public function show_header_template()
908
    {
909
        $tpl = $this->get_template('layout/show_header.tpl');
910
        $this->display($tpl);
911
    }
912
913
    /**
914
     * Show footer template.
915
     */
916
    public function show_footer_template()
917
    {
918
        $tpl = $this->get_template('layout/show_footer.tpl');
919
        $this->display($tpl);
920
    }
921
922
    /**
923
     * Sets the plugin content in a template variable.
924
     *
925
     * @param string $pluginRegion
926
     */
927
    public function set_plugin_region($pluginRegion)
928
    {
929
        if (!empty($pluginRegion)) {
930
            $regionContent = $this->plugin->load_region(
931
                $pluginRegion,
932
                $this,
933
                $this->force_plugin_load
934
            );
935
936
            $pluginList = $this->plugin->getInstalledPlugins(false);
937
            foreach ($pluginList as $plugin_name) {
938
                // The plugin_info variable is available inside the plugin index
939
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
940
941
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
942
                    $courseInfo = api_get_course_info();
943
                    if (!empty($courseInfo)) {
944
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
945
                            /** @var Plugin $plugin */
946
                            $plugin = $pluginInfo['obj'];
947
                            $regionContent .= $plugin->renderRegion($pluginRegion);
948
                        }
949
                    }
950
                } else {
951
                    continue;
952
                }
953
            }
954
955
            if (!empty($regionContent)) {
956
                $this->assign('plugin_'.$pluginRegion, $regionContent);
957
            } else {
958
                $this->assign('plugin_'.$pluginRegion, null);
959
            }
960
        }
961
962
        return null;
963
    }
964
965
    /**
966
     * @param string $template
967
     *
968
     * @return string
969
     */
970
    public function fetch($template = null)
971
    {
972
        $template = $this->twig->loadTemplate($template);
973
974
        return $template->render($this->params);
975
    }
976
977
    /**
978
     * @param string $variable
979
     * @param mixed  $value
980
     */
981
    public function assign($variable, $value = '')
982
    {
983
        $this->params[$variable] = $value;
984
    }
985
986
    /**
987
     * Render the template.
988
     *
989
     * @param string $template           The template path
990
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
991
     */
992
    public function display($template, $clearFlashMessages = true)
993
    {
994
        $this->assign('page_origin', api_get_origin());
995
        $this->assign('flash_messages', Display::getFlashToString());
996
997
        if ($clearFlashMessages) {
998
            Display::cleanFlashMessages();
999
        }
1000
1001
        echo $this->twig->render($template, $this->params);
1002
    }
1003
1004
    /**
1005
     * Adds a body class for login pages.
1006
     */
1007
    public function setLoginBodyClass()
1008
    {
1009
        $this->assign('login_class', 'section-login');
1010
    }
1011
1012
    /**
1013
     * The theme that will be used if the database is not working.
1014
     *
1015
     * @return string
1016
     */
1017
    public static function getThemeFallback()
1018
    {
1019
        $theme = api_get_configuration_value('theme_fallback');
1020
        if (empty($theme)) {
1021
            $theme = 'chamilo';
1022
        }
1023
1024
        return $theme;
1025
    }
1026
1027
    /**
1028
     * @param bool|true $setLoginForm
1029
     */
1030
    public function setLoginForm($setLoginForm = true)
1031
    {
1032
        global $loginFailed;
1033
        $userId = api_get_user_id();
1034
        if (!($userId) || api_is_anonymous($userId)) {
1035
            // Only display if the user isn't logged in.
1036
            $this->assign(
1037
                'login_language_form',
1038
                api_display_language_form(true, true)
1039
            );
1040
            if ($setLoginForm) {
1041
                $this->assign('login_form', $this->displayLoginForm());
1042
1043
                if ($loginFailed) {
1044
                    $this->assign('login_failed', $this::handleLoginFailed());
1045
                }
1046
            }
1047
        }
1048
    }
1049
1050
    /**
1051
     * @return string
1052
     */
1053
    public function handleLoginFailed()
1054
    {
1055
        $message = get_lang('InvalidId');
1056
1057
        if (!isset($_GET['error'])) {
1058
            if (api_is_self_registration_allowed()) {
1059
                $message = get_lang('InvalidForSelfRegistration');
1060
            }
1061
        } else {
1062
            switch ($_GET['error']) {
1063
                case '':
1064
                    if (api_is_self_registration_allowed()) {
1065
                        $message = get_lang('InvalidForSelfRegistration');
1066
                    }
1067
                    break;
1068
                case 'account_expired':
1069
                    $message = get_lang('AccountExpired');
1070
                    break;
1071
                case 'account_inactive':
1072
                    $message = get_lang('AccountInactive');
1073
1074
                    if (api_get_setting('allow_registration') === 'confirmation') {
1075
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1076
                        $message .= Display::url(
1077
                            get_lang('ReSendConfirmationMail'),
1078
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1079
                            ['class' => 'alert-link']
1080
                        );
1081
                    }
1082
                    break;
1083
                case 'user_password_incorrect':
1084
                    $message = get_lang('InvalidId');
1085
                    break;
1086
                case 'access_url_inactive':
1087
                    $message = get_lang('AccountURLInactive');
1088
                    break;
1089
                case 'wrong_captcha':
1090
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1091
                    break;
1092
                case 'blocked_by_captcha':
1093
                    $message = get_lang('AccountBlockedByCaptcha');
1094
                    break;
1095
                case 'multiple_connection_not_allowed':
1096
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1097
                    break;
1098
                case 'unrecognize_sso_origin':
1099
                    //$message = get_lang('SSOError');
1100
                    break;
1101
            }
1102
        }
1103
1104
        return Display::return_message($message, 'error', false);
1105
    }
1106
1107
    public static function displayCASLoginButton($label = null)
1108
    {
1109
        $form = new FormValidator(
1110
            'form-cas-login',
1111
            'POST',
1112
            $_SERVER['REQUEST_URI'],
1113
            null,
1114
            null,
1115
            FormValidator::LAYOUT_BOX_NO_LABEL
1116
        );
1117
        $form->addHidden('forceCASAuthentication', 1);
1118
        $form->addButton(
1119
            'casLoginButton',
1120
            is_null($label) ? sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution")) : $label,
1121
            api_get_setting("casLogoURL"),
1122
            'primary',
1123
            null,
1124
            'btn-block'
1125
        );
1126
1127
        return $form->returnForm();
1128
    }
1129
1130
    public static function displayCASLogoutButton($label = null)
1131
    {
1132
        $form = new FormValidator(
1133
            'form-cas-logout',
1134
            'GET',
1135
            api_get_path(WEB_PATH),
1136
            null,
1137
            null,
1138
            FormValidator::LAYOUT_BOX_NO_LABEL
1139
        );
1140
        $form->addHidden('logout', 1);
1141
        $form->addButton(
1142
            'casLogoutButton',
1143
            is_null($label) ? sprintf(get_lang('LogoutWithYourAccountFromX'), api_get_setting("Institution")) : $label,
1144
            api_get_setting("casLogoURL"),
1145
            'primary',
1146
            null,
1147
            'btn-block'
1148
        );
1149
1150
        return $form->returnForm();
1151
    }
1152
1153
    /**
1154
     * @throws Exception
1155
     *
1156
     * @return string
1157
     */
1158
    public static function displayLoginForm()
1159
    {
1160
        // Get the $cas array from app/config/auth.conf.php
1161
        global $cas;
1162
1163
        if (is_array($cas) && array_key_exists('replace_login_form', $cas) && $cas['replace_login_form']) {
1164
            return self::displayCASLoginButton();
1165
        }
1166
1167
        $form = new FormValidator(
1168
            'formLogin',
1169
            'POST',
1170
            null,
1171
            null,
1172
            null,
1173
            FormValidator::LAYOUT_BOX_NO_LABEL
1174
        );
1175
        $params = [
1176
            'id' => 'login',
1177
            'autofocus' => 'autofocus',
1178
            'icon' => 'user fa-fw',
1179
            'placeholder' => get_lang('UserName'),
1180
        ];
1181
        $browserAutoCapitalize = false;
1182
        // Avoid showing the autocapitalize option if the browser doesn't
1183
        // support it: this attribute is against the HTML5 standard
1184
        if (api_browser_support('autocapitalize')) {
1185
            $browserAutoCapitalize = false;
1186
            $params['autocapitalize'] = 'none';
1187
        }
1188
        $form->addText(
1189
            'login',
1190
            get_lang('UserName'),
1191
            true,
1192
            $params
1193
        );
1194
        $params = [
1195
            'id' => 'password',
1196
            'icon' => 'lock fa-fw',
1197
            'placeholder' => get_lang('Pass'),
1198
        ];
1199
        if ($browserAutoCapitalize) {
1200
            $params['autocapitalize'] = 'none';
1201
        }
1202
        $form->addElement(
1203
            'password',
1204
            'password',
1205
            get_lang('Pass'),
1206
            $params
1207
        );
1208
        // Captcha
1209
        $captcha = api_get_setting('allow_captcha');
1210
        $allowCaptcha = $captcha === 'true';
1211
1212
        if ($allowCaptcha) {
1213
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1214
            if ($useCaptcha) {
1215
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1216
                $options = [
1217
                    'width' => 250,
1218
                    'height' => 90,
1219
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1220
                    'sessionVar' => basename(__FILE__, '.php'),
1221
                    'imageOptions' => [
1222
                        'font_size' => 20,
1223
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1224
                        'font_file' => 'OpenSans-Regular.ttf',
1225
                        //'output' => 'gif'
1226
                    ],
1227
                ];
1228
1229
                // Minimum options using all defaults (including defaults for Image_Text):
1230
                //$options = array('callback' => 'qfcaptcha_image.php');
1231
                $captchaQuestion = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1232
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1233
1234
                $form->addElement(
1235
                    'text',
1236
                    'captcha',
1237
                    get_lang('EnterTheLettersYouSee')
1238
                );
1239
                $form->addRule(
1240
                    'captcha',
1241
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1242
                    'required',
1243
                    null,
1244
                    'client'
1245
                );
1246
                $form->addRule(
1247
                    'captcha',
1248
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1249
                    'CAPTCHA',
1250
                    $captchaQuestion
1251
                );
1252
            }
1253
        }
1254
1255
        $form->addButton(
1256
            'submitAuth',
1257
            get_lang('LoginEnter'),
1258
            null,
1259
            'primary',
1260
            null,
1261
            'btn-block'
1262
        );
1263
1264
        $html = $form->returnForm();
1265
        if (api_get_setting('openid_authentication') == 'true') {
1266
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1267
            $html .= '<div>'.openid_form().'</div>';
1268
        }
1269
1270
        $pluginKeycloak = api_get_plugin_setting('keycloak', 'tool_enable') === 'true';
1271
        $plugin = null;
1272
        if ($pluginKeycloak) {
1273
            $pluginUrl = api_get_path(WEB_PLUGIN_PATH).'keycloak/start.php?sso';
1274
            $pluginUrl = Display::url('Keycloak', $pluginUrl, ['class' => 'btn btn-primary']);
1275
            $html .= '<div>'.$pluginUrl.'</div>';
1276
        }
1277
1278
        $html .= '<div></div>';
1279
1280
        return $html;
1281
    }
1282
1283
    /**
1284
     * Returns the tutors names for the current course in session
1285
     * Function to use in Twig templates.
1286
     *
1287
     * @return string
1288
     */
1289
    public static function returnTutorsNames()
1290
    {
1291
        $em = Database::getManager();
1292
        $tutors = $em
1293
            ->createQuery('
1294
                SELECT u FROM ChamiloUserBundle:User u
1295
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1296
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1297
            ')
1298
            ->setParameters([
1299
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1300
                'session' => api_get_session_id(),
1301
                'course' => api_get_course_int_id(),
1302
            ])
1303
            ->getResult();
1304
1305
        $names = [];
1306
1307
        /** @var User $tutor */
1308
        foreach ($tutors as $tutor) {
1309
            $names[] = UserManager::formatUserFullName($tutor);
1310
        }
1311
1312
        return implode(CourseManager::USER_SEPARATOR, $names);
1313
    }
1314
1315
    /**
1316
     * Returns the teachers name for the current course
1317
     * Function to use in Twig templates.
1318
     *
1319
     * @return string
1320
     */
1321
    public static function returnTeachersNames()
1322
    {
1323
        $em = Database::getManager();
1324
        $teachers = $em
1325
            ->createQuery('
1326
                SELECT u FROM ChamiloUserBundle:User u
1327
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1328
                WHERE cu.status = :teacher_status AND cu.course = :course
1329
            ')
1330
            ->setParameters([
1331
                'teacher_status' => User::COURSE_MANAGER,
1332
                'course' => api_get_course_int_id(),
1333
            ])
1334
            ->getResult();
1335
1336
        $names = [];
1337
1338
        /** @var User $teacher */
1339
        foreach ($teachers as $teacher) {
1340
            $names[] = UserManager::formatUserFullName($teacher);
1341
        }
1342
1343
        return implode(CourseManager::USER_SEPARATOR, $names);
1344
    }
1345
1346
    /**
1347
     * @param int $code
1348
     */
1349
    public function setResponseCode($code)
1350
    {
1351
        $this->responseCode = $code;
1352
    }
1353
1354
    public function getResponseCode()
1355
    {
1356
        return $this->responseCode;
1357
    }
1358
1359
    /**
1360
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1361
     *
1362
     * @return bool Always return true because there is always a string, even if empty
1363
     */
1364
    public function assignBugNotification()
1365
    {
1366
        //@todo move this in the template
1367
        $rightFloatMenu = '';
1368
        $iconBug = Display::return_icon(
1369
            'bug.png',
1370
            get_lang('ReportABug'),
1371
            [],
1372
            ICON_SIZE_LARGE
1373
        );
1374
        if (api_get_setting('show_link_bug_notification') === 'true' && $this->user_is_logged_in) {
1375
            $rightFloatMenu = '<div class="report">
1376
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1377
                    '.$iconBug.'
1378
                </a>
1379
		        </div>';
1380
        }
1381
1382
        if (api_get_setting('show_link_ticket_notification') === 'true' &&
1383
            $this->user_is_logged_in
1384
        ) {
1385
            // by default is project_id = 1
1386
            $defaultProjectId = 1;
1387
            $iconTicket = Display::return_icon(
1388
                'help.png',
1389
                get_lang('Ticket'),
1390
                [],
1391
                ICON_SIZE_LARGE
1392
            );
1393
            $courseInfo = api_get_course_info();
1394
            $courseParams = '';
1395
            if (!empty($courseInfo)) {
1396
                $courseParams = api_get_cidreq();
1397
            }
1398
1399
            $extraParams = '';
1400
            if (api_get_configuration_value('ticket_lp_quiz_info_add')) {
1401
                if (isset($_GET['exerciseId']) && !empty($_GET['exerciseId'])) {
1402
                    $extraParams = '&exerciseId='.(int) $_GET['exerciseId'];
1403
                }
1404
1405
                if (isset($_GET['lp_id']) && !empty($_GET['lp_id'])) {
1406
                    $extraParams .= '&lpId='.(int) $_GET['lp_id'];
1407
                }
1408
            }
1409
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams.$extraParams;
1410
            $allow = TicketManager::userIsAllowInProject(api_get_user_info(), $defaultProjectId);
1411
1412
            if ($allow) {
1413
                $rightFloatMenu .= '<div class="help">
1414
                    <a href="'.$url.'" target="_blank">
1415
                        '.$iconTicket.'
1416
                    </a>
1417
                </div>';
1418
            }
1419
        }
1420
1421
        $this->assign('bug_notification', $rightFloatMenu);
1422
1423
        return true;
1424
    }
1425
1426
    /**
1427
     * Prepare the _c array for template files. The _c array contains
1428
     * information about the current course.
1429
     */
1430
    private function set_course_parameters()
1431
    {
1432
        //Setting course id
1433
        $course = api_get_course_info();
1434
        if (empty($course)) {
1435
            $this->assign('course_is_set', false);
1436
1437
            return;
1438
        }
1439
        $this->assign('course_is_set', true);
1440
        $this->course_id = $course['id'];
1441
        $_c = [
1442
            'id' => $course['real_id'],
1443
            'code' => $course['code'],
1444
            'title' => $course['name'],
1445
            'visibility' => $course['visibility'],
1446
            'language' => $course['language'],
1447
            'directory' => $course['directory'],
1448
            'session_id' => api_get_session_id(),
1449
            'user_is_teacher' => api_is_course_admin(),
1450
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
1451
        ];
1452
        $this->assign('course_code', $course['code']);
1453
        $this->assign('_c', $_c);
1454
    }
1455
1456
    /**
1457
     * Prepare the _u array for template files. The _u array contains
1458
     * information about the current user, as returned by
1459
     * api_get_user_info().
1460
     */
1461
    private function set_user_parameters()
1462
    {
1463
        $user_info = [];
1464
        $user_info['logged'] = 0;
1465
        $this->user_is_logged_in = false;
1466
        if (api_user_is_login()) {
1467
            $user_info = api_get_user_info(api_get_user_id(), true);
1468
            $user_info['logged'] = 1;
1469
1470
            $user_info['is_admin'] = 0;
1471
            if (api_is_platform_admin()) {
1472
                $user_info['is_admin'] = 1;
1473
            }
1474
1475
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1476
            $this->user_is_logged_in = true;
1477
        }
1478
        // Setting the $_u array that could be use in any template
1479
        $this->assign('_u', $user_info);
1480
    }
1481
1482
    /**
1483
     * Get an array of all the web paths available (e.g. 'web' => 'https://my.chamilo.site/').
1484
     *
1485
     * @return array
1486
     */
1487
    private function getWebPaths()
1488
    {
1489
        $queryString = empty($_SERVER['QUERY_STRING']) ? '' : $_SERVER['QUERY_STRING'];
1490
        $requestURI = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
1491
1492
        return [
1493
            'web' => api_get_path(WEB_PATH),
1494
            'web_url' => api_get_web_url(),
1495
            'web_relative' => api_get_path(REL_PATH),
1496
            'web_course' => api_get_path(WEB_COURSE_PATH),
1497
            'web_main' => api_get_path(WEB_CODE_PATH),
1498
            'web_css' => api_get_path(WEB_CSS_PATH),
1499
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
1500
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
1501
            'web_img' => api_get_path(WEB_IMG_PATH),
1502
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
1503
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
1504
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
1505
            'web_self' => api_get_self(),
1506
            'self_basename' => basename(api_get_self()),
1507
            'web_query_vars' => api_htmlentities($queryString),
1508
            'web_self_query_vars' => api_htmlentities($requestURI),
1509
            'web_cid_query' => api_get_cidreq(),
1510
            'web_rel_code' => api_get_path(REL_CODE_PATH),
1511
        ];
1512
    }
1513
1514
    /**
1515
     * Set header parameters.
1516
     *
1517
     * @param bool $sendHeaders send headers
1518
     */
1519
    private function set_header_parameters($sendHeaders)
1520
    {
1521
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1522
        $_course = api_get_course_info();
1523
        $nameTools = $this->title;
1524
        $navigation = return_navigation_array();
1525
        $this->menu_navigation = $navigation['menu_navigation'];
1526
1527
        $this->assign('system_charset', api_get_system_encoding());
1528
1529
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1530
            foreach ($httpHeadXtra as &$thisHttpHead) {
1531
                header($thisHttpHead);
1532
            }
1533
        }
1534
1535
        // Get language iso-code for this page - ignore errors
1536
        $this->assign('document_language', api_get_language_isocode());
1537
1538
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1539
1540
        $title_list = [];
1541
1542
        $title_list[] = api_get_setting('Institution');
1543
        $title_list[] = api_get_setting('siteName');
1544
1545
        if (!empty($course_title)) {
1546
            $title_list[] = $course_title;
1547
        }
1548
        if ($nameTools != '') {
1549
            $title_list[] = $nameTools;
1550
        }
1551
1552
        $title_string = '';
1553
        for ($i = 0; $i < count($title_list); $i++) {
1554
            $title_string .= $title_list[$i];
1555
            if (isset($title_list[$i + 1])) {
1556
                $item = trim($title_list[$i + 1]);
1557
                if (!empty($item)) {
1558
                    $title_string .= ' - ';
1559
                }
1560
            }
1561
        }
1562
1563
        $this->assign('title_string', $title_string);
1564
1565
        // Setting the theme and CSS files
1566
        $this->setCssFiles();
1567
        $this->set_js_files();
1568
        $this->setCssCustomFiles();
1569
1570
        $browser = api_browser_support('check_browser');
1571
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1572
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1573
            $this->assign('browser_specific_head', $browser_head);
1574
        }
1575
1576
        // Implementation of prefetch.
1577
        // See http://cdn.chamilo.org/main/img/online.png for details
1578
        $prefetch = '';
1579
        if (!empty($_configuration['cdn_enable'])) {
1580
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1581
            foreach ($_configuration['cdn'] as $host => $exts) {
1582
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1583
            }
1584
        }
1585
1586
        $this->assign('prefetch', $prefetch);
1587
        $this->assign('text_direction', api_get_text_direction());
1588
        $this->assign('section_name', 'section-'.$this_section);
1589
        $this->assignFavIcon();
1590
        $this->setHelp();
1591
1592
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1593
1594
        $this->assignAccessibilityBlock(); //Prepare the 'accessibility' var for the template
1595
1596
        // Preparing values for the menu
1597
1598
        // Logout link
1599
        $hideLogout = api_get_setting('hide_logout_button');
1600
        if ($hideLogout === 'true') {
1601
            $this->assign('logout_link', null);
1602
        } else {
1603
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1604
        }
1605
1606
        // Profile link
1607
        if (api_get_setting('allow_social_tool') == 'true') {
1608
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1609
        } else {
1610
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1611
        }
1612
1613
        $this->assign('profile_url', $profile_url);
1614
1615
        //Message link
1616
        $message_link = null;
1617
        $message_url = null;
1618
        if (api_get_setting('allow_message_tool') == 'true') {
1619
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1620
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1621
        }
1622
        $this->assign('message_link', $message_link);
1623
        $this->assign('message_url', $message_url);
1624
1625
        $pendingSurveyLink = '';
1626
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1627
        if ($show) {
1628
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1629
        }
1630
        $this->assign('pending_survey_url', $pendingSurveyLink);
1631
1632
        // Certificate Link
1633
        $allow = api_get_configuration_value('hide_my_certificate_link');
1634
        if ($allow === false) {
1635
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1636
            $certificateLink = Display::url(
1637
                get_lang('MyCertificates'),
1638
                $certificateUrl
1639
            );
1640
            $this->assign('certificate_link', $certificateLink);
1641
            $this->assign('certificate_url', $certificateUrl);
1642
        }
1643
1644
        $institution = api_get_setting('Institution');
1645
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1646
1647
        $this->assign('portal_name', $portal_name);
1648
1649
        //Menu
1650
        $menu = menuArray();
1651
        $this->assign('menu', $menu);
1652
1653
        $breadcrumb = '';
1654
        // Hide breadcrumb in LP
1655
        if ($this->show_learnpath == false) {
1656
            $breadcrumb = return_breadcrumb(
1657
                $interbreadcrumb,
1658
                $language_file,
1659
                $nameTools
1660
            );
1661
        }
1662
        $this->assign('breadcrumb', $breadcrumb);
1663
1664
        //Extra content
1665
        $extra_header = null;
1666
        if (!api_is_platform_admin()) {
1667
            $extra_header = trim(api_get_setting('header_extra_content'));
1668
        }
1669
        $this->assign('header_extra_content', $extra_header);
1670
1671
        if ($sendHeaders) {
1672
            header('Content-Type: text/html; charset='.api_get_system_encoding());
1673
            header(
1674
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1675
            );
1676
            self::addHTTPSecurityHeaders();
1677
1678
            $responseCode = $this->getResponseCode();
1679
            if (!empty($responseCode)) {
1680
                switch ($responseCode) {
1681
                    case '404':
1682
                        header("HTTP/1.0 404 Not Found");
1683
                        break;
1684
                }
1685
            }
1686
        }
1687
1688
        $this->assignSocialMeta();
1689
    }
1690
1691
    /**
1692
     * Set footer parameters.
1693
     */
1694
    private function set_footer_parameters()
1695
    {
1696
        if (api_get_setting('show_administrator_data') === 'true') {
1697
            $firstName = api_get_setting('administratorName');
1698
            $lastName = api_get_setting('administratorSurname');
1699
1700
            if (!empty($firstName) && !empty($lastName)) {
1701
                $name = api_get_person_name($firstName, $lastName);
1702
            } else {
1703
                $name = $lastName;
1704
                if (empty($lastName)) {
1705
                    $name = $firstName;
1706
                }
1707
            }
1708
1709
            $adminName = '';
1710
            // Administrator name
1711
            if (!empty($name)) {
1712
                $adminName = get_lang('Manager').' : ';
1713
                $adminName .= Display::encrypted_mailto_link(
1714
                    api_get_setting('emailAdministrator'),
1715
                    $name,
1716
                    '',
1717
                    true
1718
                );
1719
            }
1720
            $this->assign('administrator_name', $adminName);
1721
        }
1722
1723
        // Loading footer extra content
1724
        if (!api_is_platform_admin()) {
1725
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1726
            if (!empty($extra_footer)) {
1727
                $this->assign('footer_extra_content', $extra_footer);
1728
            }
1729
        }
1730
1731
        // Tutor name
1732
        if (api_get_setting('show_tutor_data') == 'true') {
1733
            // Course manager
1734
            $courseId = api_get_course_int_id();
1735
            $id_session = api_get_session_id();
1736
            if (!empty($courseId)) {
1737
                $tutor_data = '';
1738
                if ($id_session != 0) {
1739
                    $users = SessionManager::getCoachesByCourseSession($id_session, $courseId);
1740
                    $links = [];
1741
                    if (!empty($users)) {
1742
                        $coaches = [];
1743
                        foreach ($users as $userId) {
1744
                            $coaches[] = api_get_user_info($userId);
1745
                        }
1746
                        $links = array_column($coaches, 'complete_name_with_message_link');
1747
                    }
1748
                    $count = count($links);
1749
                    if ($count > 1) {
1750
                        $tutor_data .= get_lang('Coachs').' : ';
1751
                        $tutor_data .= array_to_string($links, CourseManager::USER_SEPARATOR);
1752
                    } elseif ($count === 1) {
1753
                        $tutor_data .= get_lang('Coach').' : ';
1754
                        $tutor_data .= array_to_string($links, CourseManager::USER_SEPARATOR);
1755
                    } elseif ($count === 0) {
1756
                        $tutor_data .= '';
1757
                    }
1758
                }
1759
                $this->assign('session_teachers', $tutor_data);
1760
            }
1761
        }
1762
1763
        if (api_get_setting('show_teacher_data') == 'true') {
1764
            // course manager
1765
            $courseId = api_get_course_int_id();
1766
            if (!empty($courseId)) {
1767
                $teacher_data = '';
1768
                $teachers = CourseManager::getTeachersFromCourse($courseId);
1769
                if (!empty($teachers)) {
1770
                    $teachersParsed = [];
1771
                    foreach ($teachers as $teacher) {
1772
                        $userId = $teacher['id'];
1773
                        $teachersParsed[] = api_get_user_info($userId);
1774
                    }
1775
                    $links = array_column($teachersParsed, 'complete_name_with_message_link');
1776
                    $label = get_lang('Teacher');
1777
                    if (count($links) > 1) {
1778
                        $label = get_lang('Teachers');
1779
                    }
1780
                    $teacher_data .= $label.' : '.array_to_string($links, CourseManager::USER_SEPARATOR);
1781
                }
1782
                $this->assign('teachers', $teacher_data);
1783
            }
1784
        }
1785
    }
1786
1787
    /**
1788
     * Set administrator variables.
1789
     */
1790
    private function setAdministratorParams()
1791
    {
1792
        $_admin = [
1793
            'email' => api_get_setting('emailAdministrator'),
1794
            'surname' => api_get_setting('administratorSurname'),
1795
            'name' => api_get_setting('administratorName'),
1796
            'telephone' => api_get_setting('administratorTelephone'),
1797
        ];
1798
1799
        $this->assign('_admin', $_admin);
1800
    }
1801
1802
    /**
1803
     * Manage specific HTTP headers security.
1804
     */
1805
    private function addHTTPSecurityHeaders()
1806
    {
1807
        // Implementation of HTTP headers security, as suggested and checked
1808
        // by https://securityheaders.io/
1809
        // Enable these settings in configuration.php to use them on your site
1810
        // Strict-Transport-Security
1811
        $setting = api_get_configuration_value('security_strict_transport');
1812
        if (!empty($setting)) {
1813
            header('Strict-Transport-Security: '.$setting);
1814
        }
1815
        // Content-Security-Policy
1816
        $setting = api_get_configuration_value('security_content_policy');
1817
        if (!empty($setting)) {
1818
            header('Content-Security-Policy: '.$setting);
1819
        }
1820
        $setting = api_get_configuration_value('security_content_policy_report_only');
1821
        if (!empty($setting)) {
1822
            header('Content-Security-Policy-Report-Only: '.$setting);
1823
        }
1824
        // Public-Key-Pins
1825
        $setting = api_get_configuration_value('security_public_key_pins');
1826
        if (!empty($setting)) {
1827
            header('Public-Key-Pins: '.$setting);
1828
        }
1829
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1830
        if (!empty($setting)) {
1831
            header('Public-Key-Pins-Report-Only: '.$setting);
1832
        }
1833
        // X-Frame-Options
1834
        $setting = api_get_configuration_value('security_x_frame_options');
1835
        if (!empty($setting)) {
1836
            header('X-Frame-Options: '.$setting);
1837
        }
1838
        // X-XSS-Protection
1839
        $setting = api_get_configuration_value('security_xss_protection');
1840
        if (!empty($setting)) {
1841
            header('X-XSS-Protection: '.$setting);
1842
        }
1843
        // X-Content-Type-Options
1844
        $setting = api_get_configuration_value('security_x_content_type_options');
1845
        if (!empty($setting)) {
1846
            header('X-Content-Type-Options: '.$setting);
1847
        }
1848
        // Referrer-Policy
1849
        $setting = api_get_configuration_value('security_referrer_policy');
1850
        if (!empty($setting)) {
1851
            header('Referrer-Policy: '.$setting);
1852
        }
1853
        // end of HTTP headers security block
1854
    }
1855
1856
    /**
1857
     * Assign favicon to the 'favico' template variable.
1858
     *
1859
     * @return bool Always return true because there is always at least one correct favicon.ico
1860
     */
1861
    private function assignFavIcon()
1862
    {
1863
        // Default root chamilo favicon
1864
        $favico = '<link rel="icon" href="'.api_get_path(WEB_PATH).'favicon.png" type="image/png" />';
1865
1866
        //Added to verify if in the current Chamilo Theme exist a favicon
1867
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1868
1869
        //If exist pick the current chamilo theme favicon
1870
        if (is_file($favicoThemeUrl.'favicon.png')) {
1871
            $favico = '<link rel="icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.png" type="image/png" />';
1872
        }
1873
1874
        if (api_is_multiple_url_enabled()) {
1875
            $access_url_id = api_get_current_access_url_id();
1876
            if ($access_url_id != -1) {
1877
                $url_info = api_get_access_url($access_url_id);
1878
                $url = api_remove_trailing_slash(
1879
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1880
                );
1881
                $clean_url = api_replace_dangerous_char($url);
1882
                $clean_url = str_replace('/', '-', $clean_url);
1883
                $clean_url .= '/';
1884
                $homep = api_get_path(WEB_HOME_PATH).$clean_url; //homep for Home Path
1885
                $icon_real_homep = api_get_path(SYS_HOME_PATH).$clean_url;
1886
                //we create the new dir for the new sites
1887
                if (is_file($icon_real_homep.'favicon.ico')) {
1888
                    $favico = '<link rel="icon" href="'.$homep.'favicon.png" type="image/png" />';
1889
                }
1890
            }
1891
        }
1892
1893
        $this->assign('favico', $favico);
1894
1895
        return true;
1896
    }
1897
1898
    /**
1899
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1900
     *
1901
     * @return bool Always return true (even if empty string)
1902
     */
1903
    private function assignAccessibilityBlock()
1904
    {
1905
        $resize = '';
1906
        if (api_get_setting('accessibility_font_resize') == 'true') {
1907
            $resize .= '<div class="resize_font">';
1908
            $resize .= '<div class="btn-group">';
1909
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1910
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1911
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1912
            $resize .= '</div>';
1913
            $resize .= '</div>';
1914
        }
1915
        $this->assign('accessibility', $resize);
1916
1917
        return true;
1918
    }
1919
1920
    /**
1921
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1922
     *
1923
     * @return bool Always return true (even if empty string)
1924
     */
1925
    private function assignSocialMeta()
1926
    {
1927
        $socialMeta = '';
1928
        $metaTitle = api_get_setting('meta_title');
1929
        if (!empty($metaTitle)) {
1930
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1931
            $metaSite = api_get_setting('meta_twitter_site');
1932
            if (!empty($metaSite)) {
1933
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1934
                $metaCreator = api_get_setting('meta_twitter_creator');
1935
                if (!empty($metaCreator)) {
1936
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1937
                }
1938
            }
1939
1940
            // The user badge page emits its own meta tags, so if this is
1941
            // enabled, ignore the global ones
1942
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1943
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1944
1945
            if (!$userId && !$skillId) {
1946
                // no combination of user and skill ID has been defined,
1947
                // so print the normal or course-specific OpenGraph meta tags
1948
                // Check for a course ID
1949
                $courseId = api_get_course_int_id();
1950
                // Check session ID from session/id/about (see .htaccess)
1951
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1952
1953
                if ($courseId != false) {
1954
                    // If we are inside a course (even if within a session), publish info about the course
1955
                    $course = api_get_course_entity($courseId);
1956
                    // @TODO: support right-to-left in title
1957
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1958
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1959
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
1960
1961
                    $metaDescription = api_get_setting('meta_description');
1962
                    if (!empty($course->getDescription())) {
1963
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1964
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1965
                    } elseif (!empty($metaDescription)) {
1966
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1967
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1968
                    }
1969
1970
                    $picture = CourseManager::getPicturePath($course, true);
1971
                    if (!empty($picture)) {
1972
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1973
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
1974
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1975
                    } else {
1976
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1977
                    }
1978
                } elseif ($sessionId !== 0) {
1979
                    // If we are on a session "about" screen, publish info about the session
1980
                    $em = Database::getManager();
1981
                    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
1982
1983
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1984
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1985
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."session/{$session->getId()}/about/".'" />'."\n";
1986
1987
                    $sessionValues = new ExtraFieldValue('session');
1988
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1989
                    $sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1990
1991
                    if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
1992
                        $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
1993
                        $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1994
                        $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
1995
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1996
                    } else {
1997
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1998
                    }
1999
                } else {
2000
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
2001
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
2002
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
2003
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
2004
2005
                    $metaDescription = api_get_setting('meta_description');
2006
                    if (!empty($metaDescription)) {
2007
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
2008
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
2009
                    }
2010
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
2011
                }
2012
            }
2013
        }
2014
2015
        $this->assign('social_meta', $socialMeta);
2016
2017
        return true;
2018
    }
2019
2020
    /**
2021
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
2022
     *
2023
     * @param string $imageAlt The alt attribute for the image
2024
     *
2025
     * @return string The meta image HTML tag, or empty
2026
     */
2027
    private function getMetaPortalImagePath($imageAlt = '')
2028
    {
2029
        // Load portal meta image if defined
2030
        $metaImage = api_get_setting('meta_image_path');
2031
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
2032
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
2033
        $portalImageMeta = '';
2034
        if (!empty($metaImage)) {
2035
            if (is_file($metaImageSysPath)) {
2036
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
2037
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
2038
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
2039
            }
2040
        } else {
2041
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
2042
            if (!empty($logo)) {
2043
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
2044
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
2045
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
2046
            }
2047
        }
2048
2049
        return $portalImageMeta;
2050
    }
2051
}
2052