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');
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++) {
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...
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