Passed
Push — 1.11.x ( 4a5c9d...2dc19d )
by Julito
16:15 queued 03:40
created

Template::set_header()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 16
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 29
rs 8.8333
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_plugin_setting',
153
            [
154
                'name' => 'return_message',
155
                'callable' => 'Display::return_message_and_translate',
156
            ],
157
            [
158
                'name' => 'display_page_header',
159
                'callable' => 'Display::page_header_and_translate',
160
            ],
161
            [
162
                'name' => 'display_page_subheader',
163
                'callable' => 'Display::page_subheader_and_translate',
164
            ],
165
            [
166
                'name' => 'icon',
167
                'callable' => 'Display::get_icon_path',
168
            ],
169
            [
170
                'name' => 'img',
171
                'callable' => 'Display::get_image',
172
            ],
173
            [
174
                'name' => 'format_date',
175
                'callable' => 'api_format_date',
176
            ],
177
            [
178
                'name' => 'get_template',
179
                'callable' => 'api_find_template',
180
            ],
181
            [
182
                'name' => 'date_to_time_ago',
183
                'callable' => 'Display::dateToStringAgoAndLongDate',
184
            ],
185
            [
186
                'name' => 'remove_xss',
187
                'callable' => 'Security::remove_XSS',
188
            ],
189
        ];
190
191
        foreach ($filters as $filter) {
192
            if (is_array($filter)) {
193
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
194
            } else {
195
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
196
            }
197
        }
198
199
        $functions = [
200
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
201
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
202
        ];
203
204
        foreach ($functions as $function) {
205
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
206
        }
207
208
        // Setting system variables
209
        $this->set_system_parameters();
210
211
        // Setting user variables
212
        $this->set_user_parameters();
213
214
        // Setting course variables
215
        $this->set_course_parameters();
216
217
        // Setting administrator variables
218
        $this->setAdministratorParams();
219
        //$this->setCSSEditor();
220
221
        // Header and footer are showed by default
222
        $this->set_footer($show_footer);
223
        $this->set_header($show_header);
224
225
        $this->set_header_parameters($sendHeaders);
226
        $this->set_footer_parameters();
227
228
        $defaultStyle = api_get_configuration_value('default_template');
229
        if (!empty($defaultStyle)) {
230
            $this->templateFolder = $defaultStyle;
0 ignored issues
show
Documentation Bug introduced by
It seems like $defaultStyle can also be of type boolean. However, the property $templateFolder is declared as type string. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
231
        }
232
233
        $this->assign('template', $this->templateFolder);
234
        $this->assign('locale', api_get_language_isocode());
235
        $this->assign('login_class', null);
236
237
        $allow = api_get_configuration_value('show_language_selector_in_menu');
238
        if ($allow) {
239
            $this->assign('language_form', api_display_language_form());
240
        }
241
242
        if (api_get_configuration_value('notification_event')) {
243
            $this->assign('notification_event', '1');
244
        }
245
246
        // Chamilo plugins
247
        if ($this->show_header) {
248
            if ($this->load_plugins) {
249
                $this->plugin = new AppPlugin();
250
251
                //1. Showing installed plugins in regions
252
                $pluginRegions = $this->plugin->get_plugin_regions();
253
                foreach ($pluginRegions as $region) {
254
                    $this->set_plugin_region($region);
255
                }
256
257
                //2. Loading the course plugin info
258
                global $course_plugin;
259
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
260
                    //Load plugin get_langs
261
                    $this->plugin->load_plugin_lang_variables($course_plugin);
262
                }
263
            }
264
        }
265
    }
266
267
    /**
268
     * Return the item's url key:.
269
     *
270
     *      c_id=xx&id=xx
271
     *
272
     * @param object $item
273
     *
274
     * @return string
275
     */
276
    public static function key($item)
277
    {
278
        $id = isset($item->id) ? $item->id : null;
279
        $c_id = isset($item->c_id) ? $item->c_id : null;
280
        $result = '';
281
        if ($c_id) {
282
            $result = "c_id=$c_id";
283
        }
284
        if ($id) {
285
            if ($result) {
286
                $result .= "&amp;id=$id";
287
            } else {
288
                $result .= "&amp;id=$id";
289
            }
290
        }
291
292
        return $result;
293
    }
294
295
    /**
296
     * @param string $helpInput
297
     */
298
    public function setHelp($helpInput = null)
299
    {
300
        if (!empty($helpInput)) {
301
            $help = $helpInput;
302
        } else {
303
            $help = $this->help;
304
        }
305
306
        $content = '';
307
        if (api_get_setting('enable_help_link') == 'true') {
308
            if (!empty($help)) {
309
                $help = Security::remove_XSS($help);
310
                $content = '<div class="help">';
311
                $content .= Display::url(
312
                    Display::return_icon('help.large.png', get_lang('Help')),
313
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
314
                    [
315
                        'class' => 'ajax',
316
                        'data-title' => get_lang('Help'),
317
                    ]
318
                );
319
                $content .= '</div>';
320
            }
321
        }
322
        $this->assign('help_content', $content);
323
    }
324
325
    /**
326
     * Use template system to parse the actions menu.
327
     *
328
     * @todo finish it!
329
     */
330
    public function set_actions($actions)
331
    {
332
        $action_string = '';
333
        if (!empty($actions)) {
334
            foreach ($actions as $action) {
335
                $action_string .= $action;
336
            }
337
        }
338
        $this->assign('actions', $actions);
339
    }
340
341
    /**
342
     * Shortcut to display a 1 col layout (index.php).
343
     * */
344
    public function display_one_col_template()
345
    {
346
        $tpl = $this->get_template('layout/layout_1_col.tpl');
347
        $this->display($tpl);
348
    }
349
350
    /**
351
     * Shortcut to display a 2 col layout (userportal.php).
352
     */
353
    public function display_two_col_template()
354
    {
355
        $tpl = $this->get_template('layout/layout_2_col.tpl');
356
        $this->display($tpl);
357
    }
358
359
    /**
360
     * Displays an empty template.
361
     */
362
    public function display_blank_template()
363
    {
364
        $tpl = $this->get_template('layout/blank.tpl');
365
        $this->display($tpl);
366
    }
367
368
    /**
369
     * Displays an empty template.
370
     */
371
    public function displayBlankTemplateNoHeader()
372
    {
373
        $tpl = $this->get_template('layout/blank_no_header.tpl');
374
        $this->display($tpl);
375
    }
376
377
    /**
378
     * Displays an empty template.
379
     */
380
    public function display_no_layout_template()
381
    {
382
        $tpl = $this->get_template('layout/no_layout.tpl');
383
        $this->display($tpl);
384
    }
385
386
    /**
387
     * Sets the footer visibility.
388
     *
389
     * @param bool true if we show the footer
390
     */
391
    public function set_footer($status)
392
    {
393
        $this->show_footer = $status;
394
        $this->assign('show_footer', $status);
395
    }
396
397
    /**
398
     * return true if toolbar has to be displayed for user.
399
     *
400
     * @return bool
401
     */
402
    public static function isToolBarDisplayedForUser()
403
    {
404
        //Toolbar
405
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
406
        $show_toolbar = false;
407
408
        switch ($show_admin_toolbar) {
409
            case 'do_not_show':
410
                break;
411
            case 'show_to_admin':
412
                if (api_is_platform_admin()) {
413
                    $show_toolbar = true;
414
                }
415
                break;
416
            case 'show_to_admin_and_teachers':
417
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
418
                    $show_toolbar = true;
419
                }
420
                break;
421
            case 'show_to_all':
422
                $show_toolbar = true;
423
                break;
424
        }
425
426
        return $show_toolbar;
427
    }
428
429
    /**
430
     * Sets the header visibility.
431
     *
432
     * @param bool true if we show the header
433
     */
434
    public function set_header($status)
435
    {
436
        $this->show_header = $status;
437
        $this->assign('show_header', $status);
438
439
        $show_toolbar = 0;
440
441
        if (self::isToolBarDisplayedForUser()) {
442
            $show_toolbar = 1;
443
        }
444
445
        $this->assign('show_toolbar', $show_toolbar);
446
447
        // Only if course is available
448
        $courseToolBar = '';
449
        $origin = api_get_origin();
450
        $show_course_navigation_menu = '';
451
        if (!empty($this->course_id) && $this->user_is_logged_in) {
452
            if ($origin !== 'embeddable' && api_get_setting('show_toolshortcuts') !== 'false') {
453
                // Course toolbar
454
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
455
            }
456
            if (api_get_setting('show_navigation_menu') != 'false') {
457
                // Course toolbar
458
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
459
            }
460
        }
461
        $this->assign('show_course_shortcut', $courseToolBar);
462
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
463
    }
464
465
    /**
466
     * Returns the sub-folder and filename for the given tpl file.
467
     *
468
     * If template not found in overrides/ or custom template folder, the default template will be used.
469
     *
470
     * @param string $name
471
     *
472
     * @return string
473
     */
474
    public static function findTemplateFilePath($name)
475
    {
476
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
477
478
        // Check if the tpl file is present in the main/template/overrides/ dir
479
        // Overrides is a special directory meant for temporary template
480
        // customization. It must be taken into account before anything else
481
        if (is_readable($sysTemplatePath."overrides/$name")) {
482
            return "overrides/$name";
483
        }
484
485
        $defaultFolder = api_get_configuration_value('default_template');
486
487
        // If a template folder has been manually defined, search for the right
488
        // file, and if not found, go for the same file in the default template
489
        if ($defaultFolder && $defaultFolder != 'default') {
490
            // Avoid missing template error, use the default file.
491
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
492
                return "$defaultFolder/$name";
493
            }
494
        }
495
496
        return "default/$name";
497
    }
498
499
    /**
500
     * Call non-static for Template::findTemplateFilePath.
501
     *
502
     * @see Template::findTemplateFilePath()
503
     *
504
     * @param string $name
505
     *
506
     * @return string
507
     */
508
    public function get_template($name)
509
    {
510
        return api_find_template($name);
511
    }
512
513
    /**
514
     * Get CSS themes sub-directory.
515
     *
516
     * @param string $theme
517
     *
518
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
519
     */
520
    public static function getThemeDir($theme)
521
    {
522
        $themeDir = 'themes/'.$theme.'/';
523
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
524
        if (!empty($virtualTheme)) {
525
            $virtualThemeList = api_get_themes(true);
526
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
527
            if ($isVirtualTheme) {
528
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
529
            }
530
        }
531
532
        return $themeDir;
533
    }
534
535
    /**
536
     * Set system parameters from api_get_configuration into _s array for use in TPLs
537
     * Also fills the _p array from getWebPaths().
538
     *
539
     * @uses \self::getWebPaths()
540
     */
541
    public function set_system_parameters()
542
    {
543
        // Get the interface language from global.inc.php
544
        global $language_interface;
545
        $this->theme = api_get_visual_theme();
546
        if (!empty($this->preview_theme)) {
547
            $this->theme = $this->preview_theme;
548
        }
549
550
        $this->themeDir = self::getThemeDir($this->theme);
551
552
        // Setting app paths/URLs
553
        $this->assign('_p', $this->getWebPaths());
554
555
        // Here we can add system parameters that can be use in any template
556
        $_s = [
557
            'software_name' => api_get_configuration_value('software_name'),
558
            'system_version' => api_get_configuration_value('system_version'),
559
            'site_name' => api_get_setting('siteName'),
560
            'institution' => api_get_setting('Institution'),
561
            'institution_url' => api_get_setting('InstitutionUrl'),
562
            'date' => api_format_date('now', DATE_FORMAT_LONG),
563
            'timezone' => api_get_timezone(),
564
            'gamification_mode' => api_get_setting('gamification_mode'),
565
            'language_interface' => $language_interface,
566
        ];
567
        $this->assign('_s', $_s);
568
    }
569
570
    /**
571
     * Set theme, include mainstream CSS files.
572
     *
573
     * @see setCssCustomFiles() for additional CSS sheets
574
     */
575
    public function setCssFiles()
576
    {
577
        global $disable_js_and_css_files;
578
        $css = [];
579
580
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
581
        $webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
582
583
        // Default CSS Bootstrap
584
        $bowerCSSFiles = [
585
            'fontawesome/css/font-awesome.min.css',
586
            'jquery-ui/themes/smoothness/theme.css',
587
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
588
            'mediaelement/build/mediaelementplayer.min.css',
589
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
590
            'bootstrap/dist/css/bootstrap.min.css',
591
            'jquery.scrollbar/jquery.scrollbar.css',
592
            'bootstrap-daterangepicker/daterangepicker.css',
593
            'bootstrap-select/dist/css/bootstrap-select.min.css',
594
            'select2/dist/css/select2.min.css',
595
        ];
596
597
        $hide = api_get_configuration_value('hide_flag_language_switcher');
598
599
        if ($hide === false) {
600
            $bowerCSSFiles[] = 'flag-icon-css/css/flag-icon.min.css';
601
        }
602
603
        foreach ($bowerCSSFiles as $file) {
604
            $css[] = api_get_cdn_path($webPublicPath.'assets/'.$file);
605
        }
606
607
        $css[] = $webJsPath.'mediaelement/plugins/vrview/vrview.css';
608
609
        $features = api_get_configuration_value('video_features');
610
        $defaultFeatures = [
611
            'playpause',
612
            'current',
613
            'progress',
614
            'duration',
615
            'tracks',
616
            'volume',
617
            'fullscreen',
618
            'vrview',
619
            'markersrolls',
620
        ];
621
622
        if (!empty($features) && isset($features['features'])) {
623
            foreach ($features['features'] as $feature) {
624
                if ($feature === 'vrview') {
625
                    continue;
626
                }
627
                $css[] = $webJsPath."mediaelement/plugins/$feature/$feature.min.css";
628
                $defaultFeatures[] = $feature;
629
            }
630
        }
631
632
        $css[] = $webJsPath.'chosen/chosen.css';
633
634
        if (api_is_global_chat_enabled()) {
635
            $css[] = $webJsPath.'chat/css/chat.css';
636
        }
637
        $css_file_to_string = '';
638
        foreach ($css as $file) {
639
            $css_file_to_string .= api_get_css($file);
640
        }
641
642
        if (!$disable_js_and_css_files) {
643
            $this->assign('css_static_file_to_string', $css_file_to_string);
644
        }
645
646
        $defaultFeatures = implode("','", $defaultFeatures);
647
        $this->assign('video_features', $defaultFeatures);
648
    }
649
650
    /**
651
     * Prepare custom CSS to be added at the very end of the <head> section.
652
     *
653
     * @see setCssFiles() for the mainstream CSS files
654
     */
655
    public function setCssCustomFiles()
656
    {
657
        global $disable_js_and_css_files;
658
        // Base CSS
659
        $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...
660
661
        if ($this->show_learnpath) {
662
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
663
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
664
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
665
            }
666
        }
667
        if (CustomPages::enabled()) {
668
            $cssCustomPage = api_get_path(SYS_CSS_PATH).$this->themeDir."custompage.css";
669
            if (is_file($cssCustomPage)) {
670
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'custompage.css';
671
            } else {
672
                $css[] = api_get_path(WEB_CSS_PATH).'custompage.css';
673
            }
674
        }
675
676
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
677
        $css[] = api_get_cdn_path(ChamiloApi::getEditorBlockStylePath());
678
679
        $css_file_to_string = null;
680
        foreach ($css as $file) {
681
            $css_file_to_string .= api_get_css($file);
682
        }
683
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
684
        if (SHOW_TEXT_NEAR_ICONS == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
685
            //hack in order to fix the actions buttons
686
            $css_file_to_string .= '<style>
687
                .td_actions a {
688
                    float:left;
689
                    width:100%;
690
                }
691
                .forum_message_left a {
692
                    float:left;
693
                    width:100%;
694
                }
695
                </style>';
696
        }
697
698
        $navigator_info = api_get_navigator();
699
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
700
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
701
        }
702
703
        if (!$disable_js_and_css_files) {
704
            $this->assign('css_custom_file_to_string', $css_file_to_string);
705
706
            $style_print = '';
707
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
708
                $style_print = api_get_css(
709
                    api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->theme.'/print.css'),
710
                    'print'
711
                );
712
            }
713
            $this->assign('css_style_print', $style_print);
714
        }
715
716
        // Logo
717
        $logo = return_logo($this->theme);
718
        $logoPdf = return_logo($this->theme, false);
719
        $this->assign('logo', $logo);
720
        $this->assign('logo_pdf', $logoPdf);
721
        $this->assign('show_media_element', 1);
722
    }
723
724
    /**
725
     * Declare and define the template variable that will be used to load
726
     * javascript libraries in the header.
727
     */
728
    public function set_js_files()
729
    {
730
        global $disable_js_and_css_files, $htmlHeadXtra;
731
        $isoCode = api_get_language_isocode();
732
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
733
734
        if ($isoCode == 'en') {
735
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
736
        }
737
        // JS files
738
        $js_files = [
739
            'chosen/chosen.jquery.min.js',
740
            'mediaelement/plugins/vrview/vrview.js',
741
            'mediaelement/plugins/markersrolls/markersrolls.min.js',
742
        ];
743
744
        if (api_get_setting('accessibility_font_resize') === 'true') {
745
            $js_files[] = 'fontresize.js';
746
        }
747
748
        $js_file_to_string = '';
749
        $bowerJsFiles = [
750
            'modernizr/modernizr.js',
751
            'jquery/dist/jquery.min.js',
752
            'bootstrap/dist/js/bootstrap.min.js',
753
            'jquery-ui/jquery-ui.min.js',
754
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
755
            'moment/min/moment-with-locales.js',
756
            'bootstrap-daterangepicker/daterangepicker.js',
757
            'jquery-timeago/jquery.timeago.js',
758
            'mediaelement/build/mediaelement-and-player.min.js',
759
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
760
            'image-map-resizer/js/imageMapResizer.min.js',
761
            'jquery.scrollbar/jquery.scrollbar.min.js',
762
            'readmore-js/readmore.min.js',
763
            'bootstrap-select/dist/js/bootstrap-select.min.js',
764
            $selectLink,
765
            'select2/dist/js/select2.min.js',
766
            "select2/dist/js/i18n/$isoCode.js",
767
            'js-cookie/src/js.cookie.js',
768
        ];
769
770
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
771
772
        if ($viewBySession || api_is_global_chat_enabled()) {
773
            // Do not include the global chat in LP
774
            if ($this->show_learnpath == false &&
775
                $this->show_footer == true &&
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
776
                $this->hide_global_chat == false
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
777
            ) {
778
                $js_files[] = 'chat/js/chat.js';
779
                $bowerJsFiles[] = 'linkifyjs/linkify.js';
780
                $bowerJsFiles[] = 'linkifyjs/linkify-jquery.js';
781
            }
782
        }
783
784
        $features = api_get_configuration_value('video_features');
785
        if (!empty($features) && isset($features['features'])) {
786
            foreach ($features['features'] as $feature) {
787
                if ($feature === 'vrview') {
788
                    continue;
789
                }
790
                $js_files[] = "mediaelement/plugins/$feature/$feature.min.js";
791
            }
792
        }
793
794
        if (CHAMILO_LOAD_WYSIWYG === true) {
795
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
796
        }
797
798
        if (api_get_setting('include_asciimathml_script') === 'true') {
799
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
800
        }
801
802
        // If not English and the language is supported by timepicker, localize
803
        $assetsPath = api_get_path(SYS_PUBLIC_PATH).'assets/';
804
        if ($isoCode != 'en') {
805
            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')) {
806
                $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
807
                $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
808
            }
809
        }
810
811
        foreach ($bowerJsFiles as $file) {
812
            $js_file_to_string .= '<script src="'.api_get_cdn_path(api_get_path(WEB_PUBLIC_PATH).'assets/'.$file).'"></script>'."\n";
813
        }
814
815
        foreach ($js_files as $file) {
816
            $js_file_to_string .= api_get_js($file);
817
        }
818
819
        // Loading email_editor js
820
        if (api_get_setting('allow_email_editor') === 'true') {
821
            $link = 'email_editor.php';
822
            if (!api_is_anonymous()) {
823
                $this->assign('email_editor', $link);
824
                $template = $this->get_template('mail_editor/email_link.js.tpl');
825
                $js_file_to_string .= $this->fetch($template);
826
            } else {
827
                if (api_get_configuration_value('allow_email_editor_for_anonymous')) {
828
                    $link = 'email_editor_external.php';
829
                    $this->assign('email_editor', $link);
830
                    $template = $this->get_template('mail_editor/email_link.js.tpl');
831
                    $js_file_to_string .= $this->fetch($template);
832
                }
833
            }
834
        }
835
836
        if (!$disable_js_and_css_files) {
837
            $this->assign('js_file_to_string', $js_file_to_string);
838
839
            $extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
840
            // Adding jquery ui by default
841
            $extraHeaders .= api_get_jquery_ui_js();
842
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
843
                foreach ($htmlHeadXtra as &$this_html_head) {
844
                    $extraHeaders .= $this_html_head."\n";
845
                }
846
            }
847
848
            $ajax = api_get_path(WEB_AJAX_PATH);
849
            $courseId = api_get_course_id();
850
            if (empty($courseId)) {
851
                $courseLogoutCode = '
852
                <script>
853
                function courseLogout() {
854
                }
855
                </script>';
856
            } else {
857
                $courseLogoutCode = "
858
                <script>
859
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
860
                function courseLogout() {
861
                    $.ajax({
862
                        async : false,
863
                        url: logOutUrl,
864
                        success: function (data) {
865
                            return 1;
866
                        }
867
                    });
868
                }
869
                </script>";
870
            }
871
872
            $extraHeaders .= $courseLogoutCode;
873
            $this->assign('extra_headers', $extraHeaders);
874
        }
875
    }
876
877
    /**
878
     * Special function to declare last-minute JS libraries which depend on
879
     * other things to be declared first. In particular, it might be useful
880
     * under IE9 with compatibility mode, which for some reason is getting
881
     * upset when a variable is used in a function (even if not used yet)
882
     * when this variable hasn't been defined yet.
883
     */
884
    public function set_js_files_post()
885
    {
886
        global $disable_js_and_css_files;
887
        $js_files = [];
888
        $bower = '';
889
        if (api_is_global_chat_enabled()) {
890
            //Do not include the global chat in LP
891
            if ($this->show_learnpath == false && $this->show_footer == true && $this->hide_global_chat == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
892
                $js_files[] = 'chat/js/chat.js';
893
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify.js"></script>';
894
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify-jquery.js"></script>';
895
            }
896
        }
897
        $js_file_to_string = '';
898
        foreach ($js_files as $js_file) {
899
            $js_file_to_string .= api_get_js($js_file);
900
        }
901
        if (!$disable_js_and_css_files) {
902
            $this->assign('js_file_to_string_post', $js_file_to_string.$bower);
903
        }
904
    }
905
906
    /**
907
     * Show header template.
908
     */
909
    public function show_header_template()
910
    {
911
        $tpl = $this->get_template('layout/show_header.tpl');
912
        $this->display($tpl);
913
    }
914
915
    /**
916
     * Show footer template.
917
     */
918
    public function show_footer_template()
919
    {
920
        $tpl = $this->get_template('layout/show_footer.tpl');
921
        $this->display($tpl);
922
    }
923
924
    /**
925
     * Sets the plugin content in a template variable.
926
     *
927
     * @param string $pluginRegion
928
     */
929
    public function set_plugin_region($pluginRegion)
930
    {
931
        if (!empty($pluginRegion)) {
932
            $regionContent = $this->plugin->load_region(
933
                $pluginRegion,
934
                $this,
935
                $this->force_plugin_load
936
            );
937
938
            $pluginList = $this->plugin->getInstalledPlugins(false);
939
            foreach ($pluginList as $plugin_name) {
940
                // The plugin_info variable is available inside the plugin index
941
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
942
943
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
944
                    $courseInfo = api_get_course_info();
945
                    if (!empty($courseInfo)) {
946
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
947
                            /** @var Plugin $plugin */
948
                            $plugin = $pluginInfo['obj'];
949
                            $regionContent .= $plugin->renderRegion($pluginRegion);
950
                        }
951
                    }
952
                } else {
953
                    continue;
954
                }
955
            }
956
957
            if (!empty($regionContent)) {
958
                $this->assign('plugin_'.$pluginRegion, $regionContent);
959
            } else {
960
                $this->assign('plugin_'.$pluginRegion, null);
961
            }
962
        }
963
964
        return null;
965
    }
966
967
    /**
968
     * @param string $template
969
     *
970
     * @return string
971
     */
972
    public function fetch($template = null)
973
    {
974
        $template = $this->twig->loadTemplate($template);
975
976
        return $template->render($this->params);
977
    }
978
979
    /**
980
     * @param string $variable
981
     * @param mixed  $value
982
     */
983
    public function assign($variable, $value = '')
984
    {
985
        $this->params[$variable] = $value;
986
    }
987
988
    /**
989
     * Render the template.
990
     *
991
     * @param string $template           The template path
992
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
993
     */
994
    public function display($template, $clearFlashMessages = true)
995
    {
996
        $this->assign('page_origin', api_get_origin());
997
        $this->assign('flash_messages', Display::getFlashToString());
998
999
        if ($clearFlashMessages) {
1000
            Display::cleanFlashMessages();
1001
        }
1002
1003
        echo $this->twig->render($template, $this->params);
1004
    }
1005
1006
    /**
1007
     * Adds a body class for login pages.
1008
     */
1009
    public function setLoginBodyClass()
1010
    {
1011
        $this->assign('login_class', 'section-login');
1012
    }
1013
1014
    /**
1015
     * The theme that will be used if the database is not working.
1016
     *
1017
     * @return string
1018
     */
1019
    public static function getThemeFallback()
1020
    {
1021
        $theme = api_get_configuration_value('theme_fallback');
1022
        if (empty($theme)) {
1023
            $theme = 'chamilo';
1024
        }
1025
1026
        return $theme;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $theme also could return the type boolean which is incompatible with the documented return type string.
Loading history...
1027
    }
1028
1029
    /**
1030
     * @param bool|true $setLoginForm
1031
     */
1032
    public function setLoginForm($setLoginForm = true)
1033
    {
1034
        global $loginFailed;
1035
        $userId = api_get_user_id();
1036
        if (!($userId) || api_is_anonymous($userId)) {
1037
            // Only display if the user isn't logged in.
1038
            $this->assign(
1039
                'login_language_form',
1040
                api_display_language_form(true, true)
1041
            );
1042
            if ($setLoginForm) {
1043
                $this->assign('login_form', $this->displayLoginForm());
1044
1045
                if ($loginFailed) {
1046
                    $this->assign('login_failed', $this::handleLoginFailed());
0 ignored issues
show
Bug Best Practice introduced by
The method Template::handleLoginFailed() is not static, but was called statically. ( Ignorable by Annotation )

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

1046
                    $this->assign('login_failed', $this::/** @scrutinizer ignore-call */ handleLoginFailed());
Loading history...
1047
                }
1048
            }
1049
        }
1050
    }
1051
1052
    /**
1053
     * @return string
1054
     */
1055
    public function handleLoginFailed()
1056
    {
1057
        $message = get_lang('InvalidId');
1058
1059
        if (!isset($_GET['error'])) {
1060
            if (api_is_self_registration_allowed()) {
1061
                $message = get_lang('InvalidForSelfRegistration');
1062
            }
1063
        } else {
1064
            switch ($_GET['error']) {
1065
                case '':
1066
                    if (api_is_self_registration_allowed()) {
1067
                        $message = get_lang('InvalidForSelfRegistration');
1068
                    }
1069
                    break;
1070
                case 'account_expired':
1071
                    $message = get_lang('AccountExpired');
1072
                    break;
1073
                case 'account_inactive':
1074
                    $message = get_lang('AccountInactive');
1075
1076
                    if (api_get_setting('allow_registration') === 'confirmation') {
1077
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1078
                        $message .= Display::url(
1079
                            get_lang('ReSendConfirmationMail'),
1080
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1081
                            ['class' => 'alert-link']
1082
                        );
1083
                    }
1084
                    break;
1085
                case 'user_password_incorrect':
1086
                    $message = get_lang('InvalidId');
1087
                    break;
1088
                case 'access_url_inactive':
1089
                    $message = get_lang('AccountURLInactive');
1090
                    break;
1091
                case 'wrong_captcha':
1092
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1093
                    break;
1094
                case 'blocked_by_captcha':
1095
                    $message = get_lang('AccountBlockedByCaptcha');
1096
                    break;
1097
                case 'multiple_connection_not_allowed':
1098
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1099
                    break;
1100
                case 'unrecognize_sso_origin':
1101
                    //$message = get_lang('SSOError');
1102
                    break;
1103
            }
1104
        }
1105
1106
        return Display::return_message($message, 'error', false);
1107
    }
1108
1109
    public static function displayCASLoginButton($label = null)
1110
    {
1111
        $form = new FormValidator(
1112
            'form-cas-login',
1113
            'POST',
1114
            $_SERVER['REQUEST_URI'],
1115
            null,
1116
            null,
1117
            FormValidator::LAYOUT_BOX_NO_LABEL
1118
        );
1119
        $form->addHidden('forceCASAuthentication', 1);
1120
        $form->addButton(
1121
            'casLoginButton',
1122
            is_null($label) ? sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution")) : $label,
1123
            api_get_setting("casLogoURL"),
1124
            'primary',
1125
            null,
1126
            'btn-block'
1127
        );
1128
1129
        return $form->returnForm();
1130
    }
1131
1132
    public static function displayCASLogoutButton($label = null)
1133
    {
1134
        $form = new FormValidator(
1135
            'form-cas-logout',
1136
            'GET',
1137
            api_get_path(WEB_PATH),
1138
            null,
1139
            null,
1140
            FormValidator::LAYOUT_BOX_NO_LABEL
1141
        );
1142
        $form->addHidden('logout', 1);
1143
        $form->addButton(
1144
            'casLogoutButton',
1145
            is_null($label) ? sprintf(get_lang('LogoutWithYourAccountFromX'), api_get_setting("Institution")) : $label,
1146
            api_get_setting("casLogoURL"),
1147
            'primary',
1148
            null,
1149
            'btn-block'
1150
        );
1151
1152
        return $form->returnForm();
1153
    }
1154
1155
    /**
1156
     * @throws Exception
1157
     *
1158
     * @return string
1159
     */
1160
    public static function displayLoginForm()
1161
    {
1162
        // Get the $cas array from app/config/auth.conf.php
1163
        global $cas;
1164
1165
        if (is_array($cas) && array_key_exists('replace_login_form', $cas) && $cas['replace_login_form']) {
1166
            return self::displayCASLoginButton();
1167
        }
1168
1169
        $form = new FormValidator(
1170
            'formLogin',
1171
            'POST',
1172
            null,
1173
            null,
1174
            null,
1175
            FormValidator::LAYOUT_BOX_NO_LABEL
1176
        );
1177
        $params = [
1178
            'id' => 'login',
1179
            'autofocus' => 'autofocus',
1180
            'icon' => 'user fa-fw',
1181
            'placeholder' => get_lang('UserName'),
1182
        ];
1183
        $browserAutoCapitalize = false;
1184
        // Avoid showing the autocapitalize option if the browser doesn't
1185
        // support it: this attribute is against the HTML5 standard
1186
        if (api_browser_support('autocapitalize')) {
1187
            $browserAutoCapitalize = false;
1188
            $params['autocapitalize'] = 'none';
1189
        }
1190
        $form->addText(
1191
            'login',
1192
            get_lang('UserName'),
1193
            true,
1194
            $params
1195
        );
1196
        $params = [
1197
            'id' => 'password',
1198
            'icon' => 'lock fa-fw',
1199
            'placeholder' => get_lang('Pass'),
1200
        ];
1201
        if ($browserAutoCapitalize) {
1202
            $params['autocapitalize'] = 'none';
1203
        }
1204
        $form->addElement(
1205
            'password',
1206
            'password',
1207
            get_lang('Pass'),
1208
            $params
1209
        );
1210
        // Captcha
1211
        $captcha = api_get_setting('allow_captcha');
1212
        $allowCaptcha = $captcha === 'true';
1213
1214
        if ($allowCaptcha) {
1215
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1216
            if ($useCaptcha) {
1217
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1218
                $options = [
1219
                    'width' => 250,
1220
                    'height' => 90,
1221
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1222
                    'sessionVar' => basename(__FILE__, '.php'),
1223
                    'imageOptions' => [
1224
                        'font_size' => 20,
1225
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1226
                        'font_file' => 'OpenSans-Regular.ttf',
1227
                        //'output' => 'gif'
1228
                    ],
1229
                ];
1230
1231
                // Minimum options using all defaults (including defaults for Image_Text):
1232
                //$options = array('callback' => 'qfcaptcha_image.php');
1233
                $captchaQuestion = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1234
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1235
1236
                $form->addElement(
1237
                    'text',
1238
                    'captcha',
1239
                    get_lang('EnterTheLettersYouSee')
1240
                );
1241
                $form->addRule(
1242
                    'captcha',
1243
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1244
                    'required',
1245
                    null,
1246
                    'client'
1247
                );
1248
                $form->addRule(
1249
                    'captcha',
1250
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1251
                    'CAPTCHA',
1252
                    $captchaQuestion
1253
                );
1254
            }
1255
        }
1256
1257
        $form->addButton(
1258
            'submitAuth',
1259
            get_lang('LoginEnter'),
1260
            null,
1261
            'primary',
1262
            null,
1263
            'btn-block'
1264
        );
1265
1266
        $html = $form->returnForm();
1267
        if (api_get_setting('openid_authentication') == 'true') {
1268
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1269
            $html .= '<div>'.openid_form().'</div>';
0 ignored issues
show
Bug introduced by
The function openid_form was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1269
            $html .= '<div>'./** @scrutinizer ignore-call */ openid_form().'</div>';
Loading history...
1270
        }
1271
1272
        $pluginKeycloak = api_get_plugin_setting('keycloak', 'tool_enable') === 'true';
1273
        $plugin = null;
1274
        if ($pluginKeycloak) {
1275
            $pluginUrl = api_get_path(WEB_PLUGIN_PATH).'keycloak/start.php?sso';
1276
            $pluginUrl = Display::url('Keycloak', $pluginUrl, ['class' => 'btn btn-primary']);
1277
            $html .= '<div>'.$pluginUrl.'</div>';
1278
        }
1279
1280
        $html .= '<div></div>';
1281
1282
        return $html;
1283
    }
1284
1285
    /**
1286
     * Returns the tutors names for the current course in session
1287
     * Function to use in Twig templates.
1288
     *
1289
     * @return string
1290
     */
1291
    public static function returnTutorsNames()
1292
    {
1293
        $em = Database::getManager();
1294
        $tutors = $em
1295
            ->createQuery('
1296
                SELECT u FROM ChamiloUserBundle:User u
1297
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1298
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1299
            ')
1300
            ->setParameters([
1301
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1302
                'session' => api_get_session_id(),
1303
                'course' => api_get_course_int_id(),
1304
            ])
1305
            ->getResult();
1306
1307
        $names = [];
1308
1309
        /** @var User $tutor */
1310
        foreach ($tutors as $tutor) {
1311
            $names[] = UserManager::formatUserFullName($tutor);
1312
        }
1313
1314
        return implode(CourseManager::USER_SEPARATOR, $names);
1315
    }
1316
1317
    /**
1318
     * Returns the teachers name for the current course
1319
     * Function to use in Twig templates.
1320
     *
1321
     * @return string
1322
     */
1323
    public static function returnTeachersNames()
1324
    {
1325
        $em = Database::getManager();
1326
        $teachers = $em
1327
            ->createQuery('
1328
                SELECT u FROM ChamiloUserBundle:User u
1329
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1330
                WHERE cu.status = :teacher_status AND cu.course = :course
1331
            ')
1332
            ->setParameters([
1333
                'teacher_status' => User::COURSE_MANAGER,
1334
                'course' => api_get_course_int_id(),
1335
            ])
1336
            ->getResult();
1337
1338
        $names = [];
1339
1340
        /** @var User $teacher */
1341
        foreach ($teachers as $teacher) {
1342
            $names[] = UserManager::formatUserFullName($teacher);
1343
        }
1344
1345
        return implode(CourseManager::USER_SEPARATOR, $names);
1346
    }
1347
1348
    /**
1349
     * @param int $code
1350
     */
1351
    public function setResponseCode($code)
1352
    {
1353
        $this->responseCode = $code;
1354
    }
1355
1356
    public function getResponseCode()
1357
    {
1358
        return $this->responseCode;
1359
    }
1360
1361
    /**
1362
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1363
     *
1364
     * @return bool Always return true because there is always a string, even if empty
1365
     */
1366
    public function assignBugNotification()
1367
    {
1368
        //@todo move this in the template
1369
        $rightFloatMenu = '';
1370
        $iconBug = Display::return_icon(
1371
            'bug.png',
1372
            get_lang('ReportABug'),
1373
            [],
1374
            ICON_SIZE_LARGE
1375
        );
1376
        if (api_get_setting('show_link_bug_notification') === 'true' && $this->user_is_logged_in) {
1377
            $rightFloatMenu = '<div class="report">
1378
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1379
                    '.$iconBug.'
1380
                </a>
1381
		        </div>';
1382
        }
1383
1384
        if (api_get_setting('show_link_ticket_notification') === 'true' &&
1385
            $this->user_is_logged_in
1386
        ) {
1387
            // by default is project_id = 1
1388
            $defaultProjectId = 1;
1389
            $iconTicket = Display::return_icon(
1390
                'help.png',
1391
                get_lang('Ticket'),
1392
                [],
1393
                ICON_SIZE_LARGE
1394
            );
1395
            $courseInfo = api_get_course_info();
1396
            $courseParams = '';
1397
            if (!empty($courseInfo)) {
1398
                $courseParams = api_get_cidreq();
1399
            }
1400
1401
            $extraParams = '';
1402
            if (api_get_configuration_value('ticket_lp_quiz_info_add')) {
1403
                if (isset($_GET['exerciseId']) && !empty($_GET['exerciseId'])) {
1404
                    $extraParams = '&exerciseId='.(int) $_GET['exerciseId'];
1405
                }
1406
1407
                if (isset($_GET['lp_id']) && !empty($_GET['lp_id'])) {
1408
                    $extraParams .= '&lpId='.(int) $_GET['lp_id'];
1409
                }
1410
            }
1411
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams.$extraParams;
1412
            $allow = TicketManager::userIsAllowInProject(api_get_user_info(), $defaultProjectId);
1413
1414
            if ($allow) {
1415
                $rightFloatMenu .= '<div class="help">
1416
                    <a href="'.$url.'" target="_blank">
1417
                        '.$iconTicket.'
1418
                    </a>
1419
                </div>';
1420
            }
1421
        }
1422
1423
        $this->assign('bug_notification', $rightFloatMenu);
1424
1425
        return true;
1426
    }
1427
1428
    /**
1429
     * Prepare the _c array for template files. The _c array contains
1430
     * information about the current course.
1431
     */
1432
    private function set_course_parameters()
1433
    {
1434
        //Setting course id
1435
        $course = api_get_course_info();
1436
        if (empty($course)) {
1437
            $this->assign('course_is_set', false);
1438
1439
            return;
1440
        }
1441
        $this->assign('course_is_set', true);
1442
        $this->course_id = $course['id'];
1443
        $_c = [
1444
            'id' => $course['real_id'],
1445
            'code' => $course['code'],
1446
            'title' => $course['name'],
1447
            'visibility' => $course['visibility'],
1448
            'language' => $course['language'],
1449
            'directory' => $course['directory'],
1450
            'session_id' => api_get_session_id(),
1451
            'user_is_teacher' => api_is_course_admin(),
1452
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
1453
        ];
1454
        $this->assign('course_code', $course['code']);
1455
        $this->assign('_c', $_c);
1456
    }
1457
1458
    /**
1459
     * Prepare the _u array for template files. The _u array contains
1460
     * information about the current user, as returned by
1461
     * api_get_user_info().
1462
     */
1463
    private function set_user_parameters()
1464
    {
1465
        $user_info = [];
1466
        $user_info['logged'] = 0;
1467
        $this->user_is_logged_in = false;
1468
        if (api_user_is_login()) {
1469
            $user_info = api_get_user_info(api_get_user_id(), true);
1470
            $user_info['logged'] = 1;
1471
1472
            $user_info['is_admin'] = 0;
1473
            if (api_is_platform_admin()) {
1474
                $user_info['is_admin'] = 1;
1475
            }
1476
1477
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1478
            $this->user_is_logged_in = true;
1479
        }
1480
        // Setting the $_u array that could be use in any template
1481
        $this->assign('_u', $user_info);
1482
    }
1483
1484
    /**
1485
     * Get an array of all the web paths available (e.g. 'web' => 'https://my.chamilo.site/').
1486
     *
1487
     * @return array
1488
     */
1489
    private function getWebPaths()
1490
    {
1491
        $queryString = empty($_SERVER['QUERY_STRING']) ? '' : $_SERVER['QUERY_STRING'];
1492
        $requestURI = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
1493
1494
        return [
1495
            'web' => api_get_path(WEB_PATH),
1496
            'web_url' => api_get_web_url(),
1497
            'web_relative' => api_get_path(REL_PATH),
1498
            'web_course' => api_get_path(WEB_COURSE_PATH),
1499
            'web_main' => api_get_path(WEB_CODE_PATH),
1500
            'web_css' => api_get_path(WEB_CSS_PATH),
1501
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
1502
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
1503
            'web_img' => api_get_path(WEB_IMG_PATH),
1504
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
1505
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
1506
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
1507
            'web_self' => api_get_self(),
1508
            'self_basename' => basename(api_get_self()),
1509
            'web_query_vars' => api_htmlentities($queryString),
1510
            'web_self_query_vars' => api_htmlentities($requestURI),
1511
            'web_cid_query' => api_get_cidreq(),
1512
            'web_rel_code' => api_get_path(REL_CODE_PATH),
1513
        ];
1514
    }
1515
1516
    /**
1517
     * Set header parameters.
1518
     *
1519
     * @param bool $sendHeaders send headers
1520
     */
1521
    private function set_header_parameters($sendHeaders)
1522
    {
1523
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1524
        $_course = api_get_course_info();
1525
        $nameTools = $this->title;
1526
        $navigation = return_navigation_array();
1527
        $this->menu_navigation = $navigation['menu_navigation'];
1528
1529
        $this->assign('system_charset', api_get_system_encoding());
1530
1531
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1532
            foreach ($httpHeadXtra as &$thisHttpHead) {
1533
                header($thisHttpHead);
1534
            }
1535
        }
1536
1537
        // Get language iso-code for this page - ignore errors
1538
        $this->assign('document_language', api_get_language_isocode());
1539
1540
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1541
1542
        $title_list = [];
1543
1544
        $title_list[] = api_get_setting('Institution');
1545
        $title_list[] = api_get_setting('siteName');
1546
1547
        if (!empty($course_title)) {
1548
            $title_list[] = $course_title;
1549
        }
1550
        if ($nameTools != '') {
1551
            $title_list[] = $nameTools;
1552
        }
1553
1554
        $title_string = '';
1555
        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...
1556
            $title_string .= $title_list[$i];
1557
            if (isset($title_list[$i + 1])) {
1558
                $item = trim($title_list[$i + 1]);
1559
                if (!empty($item)) {
1560
                    $title_string .= ' - ';
1561
                }
1562
            }
1563
        }
1564
1565
        $this->assign('title_string', $title_string);
1566
1567
        // Setting the theme and CSS files
1568
        $this->setCssFiles();
1569
        $this->set_js_files();
1570
        $this->setCssCustomFiles();
1571
1572
        $browser = api_browser_support('check_browser');
1573
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1574
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1575
            $this->assign('browser_specific_head', $browser_head);
1576
        }
1577
1578
        // Implementation of prefetch.
1579
        // See http://cdn.chamilo.org/main/img/online.png for details
1580
        $prefetch = '';
1581
        if (!empty($_configuration['cdn_enable'])) {
1582
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1583
            foreach ($_configuration['cdn'] as $host => $exts) {
1584
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1585
            }
1586
        }
1587
1588
        $this->assign('prefetch', $prefetch);
1589
        $this->assign('text_direction', api_get_text_direction());
1590
        $this->assign('section_name', 'section-'.$this_section);
1591
        $this->assignFavIcon();
1592
        $this->setHelp();
1593
1594
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1595
1596
        $this->assignAccessibilityBlock(); //Prepare the 'accessibility' var for the template
1597
1598
        // Preparing values for the menu
1599
1600
        // Logout link
1601
        $hideLogout = api_get_setting('hide_logout_button');
1602
        if ($hideLogout === 'true') {
1603
            $this->assign('logout_link', null);
1604
        } else {
1605
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1606
        }
1607
1608
        // Profile link
1609
        if (api_get_setting('allow_social_tool') == 'true') {
1610
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1611
        } else {
1612
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1613
        }
1614
1615
        $this->assign('profile_url', $profile_url);
1616
1617
        //Message link
1618
        $message_link = null;
1619
        $message_url = null;
1620
        if (api_get_setting('allow_message_tool') == 'true') {
1621
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1622
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1623
        }
1624
        $this->assign('message_link', $message_link);
1625
        $this->assign('message_url', $message_url);
1626
1627
        $pendingSurveyLink = '';
1628
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1629
        if ($show) {
1630
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1631
        }
1632
        $this->assign('pending_survey_url', $pendingSurveyLink);
1633
1634
        // Certificate Link
1635
        $allow = api_get_configuration_value('hide_my_certificate_link');
1636
        if ($allow === false) {
1637
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1638
            $certificateLink = Display::url(
1639
                get_lang('MyCertificates'),
1640
                $certificateUrl
1641
            );
1642
            $this->assign('certificate_link', $certificateLink);
1643
            $this->assign('certificate_url', $certificateUrl);
1644
        }
1645
1646
        $institution = api_get_setting('Institution');
1647
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1648
1649
        $this->assign('portal_name', $portal_name);
1650
1651
        //Menu
1652
        $menu = menuArray();
1653
        $this->assign('menu', $menu);
1654
1655
        $breadcrumb = '';
1656
        // Hide breadcrumb in LP
1657
        if ($this->show_learnpath == false) {
1658
            $breadcrumb = return_breadcrumb(
1659
                $interbreadcrumb,
1660
                $language_file,
1661
                $nameTools
1662
            );
1663
        }
1664
        $this->assign('breadcrumb', $breadcrumb);
1665
1666
        //Extra content
1667
        $extra_header = null;
1668
        if (!api_is_platform_admin()) {
1669
            $extra_header = trim(api_get_setting('header_extra_content'));
1670
        }
1671
        $this->assign('header_extra_content', $extra_header);
1672
1673
        if ($sendHeaders) {
1674
            header('Content-Type: text/html; charset='.api_get_system_encoding());
1675
            header(
1676
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1677
            );
1678
            self::addHTTPSecurityHeaders();
0 ignored issues
show
Bug Best Practice introduced by
The method Template::addHTTPSecurityHeaders() is not static, but was called statically. ( Ignorable by Annotation )

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

1678
            self::/** @scrutinizer ignore-call */ 
1679
                  addHTTPSecurityHeaders();
Loading history...
1679
1680
            $responseCode = $this->getResponseCode();
1681
            if (!empty($responseCode)) {
1682
                switch ($responseCode) {
1683
                    case '404':
1684
                        header("HTTP/1.0 404 Not Found");
1685
                        break;
1686
                }
1687
            }
1688
        }
1689
1690
        $this->assignSocialMeta();
1691
    }
1692
1693
    /**
1694
     * Set footer parameters.
1695
     */
1696
    private function set_footer_parameters()
1697
    {
1698
        if (api_get_setting('show_administrator_data') === 'true') {
1699
            $firstName = api_get_setting('administratorName');
1700
            $lastName = api_get_setting('administratorSurname');
1701
1702
            if (!empty($firstName) && !empty($lastName)) {
1703
                $name = api_get_person_name($firstName, $lastName);
1704
            } else {
1705
                $name = $lastName;
1706
                if (empty($lastName)) {
1707
                    $name = $firstName;
1708
                }
1709
            }
1710
1711
            $adminName = '';
1712
            // Administrator name
1713
            if (!empty($name)) {
1714
                $adminName = get_lang('Manager').' : ';
1715
                $adminName .= Display::encrypted_mailto_link(
1716
                    api_get_setting('emailAdministrator'),
1717
                    $name,
1718
                    '',
1719
                    true
1720
                );
1721
            }
1722
            $this->assign('administrator_name', $adminName);
1723
        }
1724
1725
        // Loading footer extra content
1726
        if (!api_is_platform_admin()) {
1727
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1728
            if (!empty($extra_footer)) {
1729
                $this->assign('footer_extra_content', $extra_footer);
1730
            }
1731
        }
1732
1733
        // Tutor name
1734
        if (api_get_setting('show_tutor_data') == 'true') {
1735
            // Course manager
1736
            $courseId = api_get_course_int_id();
1737
            $id_session = api_get_session_id();
1738
            if (!empty($courseId)) {
1739
                $tutor_data = '';
1740
                if ($id_session != 0) {
1741
                    $users = SessionManager::getCoachesByCourseSession($id_session, $courseId);
1742
                    $links = [];
1743
                    if (!empty($users)) {
1744
                        $coaches = [];
1745
                        foreach ($users as $userId) {
1746
                            $coaches[] = api_get_user_info($userId);
1747
                        }
1748
                        $links = array_column($coaches, 'complete_name_with_message_link');
1749
                    }
1750
                    $count = count($links);
1751
                    if ($count > 1) {
1752
                        $tutor_data .= get_lang('Coachs').' : ';
1753
                        $tutor_data .= array_to_string($links, CourseManager::USER_SEPARATOR);
1754
                    } elseif ($count === 1) {
1755
                        $tutor_data .= get_lang('Coach').' : ';
1756
                        $tutor_data .= array_to_string($links, CourseManager::USER_SEPARATOR);
1757
                    } elseif ($count === 0) {
1758
                        $tutor_data .= '';
1759
                    }
1760
                }
1761
                $this->assign('session_teachers', $tutor_data);
1762
            }
1763
        }
1764
1765
        if (api_get_setting('show_teacher_data') == 'true') {
1766
            // course manager
1767
            $courseId = api_get_course_int_id();
1768
            if (!empty($courseId)) {
1769
                $teacher_data = '';
1770
                $teachers = CourseManager::getTeachersFromCourse($courseId);
1771
                if (!empty($teachers)) {
1772
                    $teachersParsed = [];
1773
                    foreach ($teachers as $teacher) {
1774
                        $userId = $teacher['id'];
1775
                        $teachersParsed[] = api_get_user_info($userId);
1776
                    }
1777
                    $links = array_column($teachersParsed, 'complete_name_with_message_link');
1778
                    $label = get_lang('Teacher');
1779
                    if (count($links) > 1) {
1780
                        $label = get_lang('Teachers');
1781
                    }
1782
                    $teacher_data .= $label.' : '.array_to_string($links, CourseManager::USER_SEPARATOR);
1783
                }
1784
                $this->assign('teachers', $teacher_data);
1785
            }
1786
        }
1787
    }
1788
1789
    /**
1790
     * Set administrator variables.
1791
     */
1792
    private function setAdministratorParams()
1793
    {
1794
        $_admin = [
1795
            'email' => api_get_setting('emailAdministrator'),
1796
            'surname' => api_get_setting('administratorSurname'),
1797
            'name' => api_get_setting('administratorName'),
1798
            'telephone' => api_get_setting('administratorTelephone'),
1799
        ];
1800
1801
        $this->assign('_admin', $_admin);
1802
    }
1803
1804
    /**
1805
     * Manage specific HTTP headers security.
1806
     */
1807
    private function addHTTPSecurityHeaders()
1808
    {
1809
        // Implementation of HTTP headers security, as suggested and checked
1810
        // by https://securityheaders.io/
1811
        // Enable these settings in configuration.php to use them on your site
1812
        // Strict-Transport-Security
1813
        $setting = api_get_configuration_value('security_strict_transport');
1814
        if (!empty($setting)) {
1815
            header('Strict-Transport-Security: '.$setting);
1816
        }
1817
        // Content-Security-Policy
1818
        $setting = api_get_configuration_value('security_content_policy');
1819
        if (!empty($setting)) {
1820
            header('Content-Security-Policy: '.$setting);
1821
        }
1822
        $setting = api_get_configuration_value('security_content_policy_report_only');
1823
        if (!empty($setting)) {
1824
            header('Content-Security-Policy-Report-Only: '.$setting);
1825
        }
1826
        // Public-Key-Pins
1827
        $setting = api_get_configuration_value('security_public_key_pins');
1828
        if (!empty($setting)) {
1829
            header('Public-Key-Pins: '.$setting);
1830
        }
1831
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1832
        if (!empty($setting)) {
1833
            header('Public-Key-Pins-Report-Only: '.$setting);
1834
        }
1835
        // X-Frame-Options
1836
        $setting = api_get_configuration_value('security_x_frame_options');
1837
        if (!empty($setting)) {
1838
            header('X-Frame-Options: '.$setting);
1839
        }
1840
        // X-XSS-Protection
1841
        $setting = api_get_configuration_value('security_xss_protection');
1842
        if (!empty($setting)) {
1843
            header('X-XSS-Protection: '.$setting);
1844
        }
1845
        // X-Content-Type-Options
1846
        $setting = api_get_configuration_value('security_x_content_type_options');
1847
        if (!empty($setting)) {
1848
            header('X-Content-Type-Options: '.$setting);
1849
        }
1850
        // Referrer-Policy
1851
        $setting = api_get_configuration_value('security_referrer_policy');
1852
        if (!empty($setting)) {
1853
            header('Referrer-Policy: '.$setting);
1854
        }
1855
        // end of HTTP headers security block
1856
    }
1857
1858
    /**
1859
     * Assign favicon to the 'favico' template variable.
1860
     *
1861
     * @return bool Always return true because there is always at least one correct favicon.ico
1862
     */
1863
    private function assignFavIcon()
1864
    {
1865
        // Default root chamilo favicon
1866
        $favico = '<link rel="icon" href="'.api_get_path(WEB_PATH).'favicon.png" type="image/png" />';
1867
1868
        //Added to verify if in the current Chamilo Theme exist a favicon
1869
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1870
1871
        //If exist pick the current chamilo theme favicon
1872
        if (is_file($favicoThemeUrl.'favicon.png')) {
1873
            $favico = '<link rel="icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.png" type="image/png" />';
1874
        }
1875
1876
        if (api_is_multiple_url_enabled()) {
1877
            $access_url_id = api_get_current_access_url_id();
1878
            if ($access_url_id != -1) {
1879
                $url_info = api_get_access_url($access_url_id);
1880
                $url = api_remove_trailing_slash(
1881
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1882
                );
1883
                $clean_url = api_replace_dangerous_char($url);
1884
                $clean_url = str_replace('/', '-', $clean_url);
1885
                $clean_url .= '/';
1886
                $homep = api_get_path(WEB_HOME_PATH).$clean_url; //homep for Home Path
1887
                $icon_real_homep = api_get_path(SYS_HOME_PATH).$clean_url;
1888
                //we create the new dir for the new sites
1889
                if (is_file($icon_real_homep.'favicon.ico')) {
1890
                    $favico = '<link rel="icon" href="'.$homep.'favicon.png" type="image/png" />';
1891
                }
1892
            }
1893
        }
1894
1895
        $this->assign('favico', $favico);
1896
1897
        return true;
1898
    }
1899
1900
    /**
1901
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1902
     *
1903
     * @return bool Always return true (even if empty string)
1904
     */
1905
    private function assignAccessibilityBlock()
1906
    {
1907
        $resize = '';
1908
        if (api_get_setting('accessibility_font_resize') == 'true') {
1909
            $resize .= '<div class="resize_font">';
1910
            $resize .= '<div class="btn-group">';
1911
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1912
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1913
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1914
            $resize .= '</div>';
1915
            $resize .= '</div>';
1916
        }
1917
        $this->assign('accessibility', $resize);
1918
1919
        return true;
1920
    }
1921
1922
    /**
1923
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1924
     *
1925
     * @return bool Always return true (even if empty string)
1926
     */
1927
    private function assignSocialMeta()
1928
    {
1929
        $socialMeta = '';
1930
        $metaTitle = api_get_setting('meta_title');
1931
        if (!empty($metaTitle)) {
1932
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1933
            $metaSite = api_get_setting('meta_twitter_site');
1934
            if (!empty($metaSite)) {
1935
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1936
                $metaCreator = api_get_setting('meta_twitter_creator');
1937
                if (!empty($metaCreator)) {
1938
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1939
                }
1940
            }
1941
1942
            // The user badge page emits its own meta tags, so if this is
1943
            // enabled, ignore the global ones
1944
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1945
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1946
1947
            if (!$userId && !$skillId) {
1948
                // no combination of user and skill ID has been defined,
1949
                // so print the normal or course-specific OpenGraph meta tags
1950
                // Check for a course ID
1951
                $courseId = api_get_course_int_id();
1952
                // Check session ID from session/id/about (see .htaccess)
1953
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1954
1955
                if ($courseId != false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $courseId of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
1956
                    // If we are inside a course (even if within a session), publish info about the course
1957
                    $course = api_get_course_entity($courseId);
1958
                    // @TODO: support right-to-left in title
1959
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1960
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1961
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
1962
1963
                    $metaDescription = api_get_setting('meta_description');
1964
                    if (!empty($course->getDescription())) {
1965
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1966
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1967
                    } elseif (!empty($metaDescription)) {
1968
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1969
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1970
                    }
1971
1972
                    $picture = CourseManager::getPicturePath($course, true);
1973
                    if (!empty($picture)) {
1974
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1975
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
1976
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1977
                    } else {
1978
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1979
                    }
1980
                } elseif ($sessionId !== 0) {
1981
                    // If we are on a session "about" screen, publish info about the session
1982
                    $em = Database::getManager();
1983
                    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
1984
1985
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1986
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1987
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."session/{$session->getId()}/about/".'" />'."\n";
1988
1989
                    $sessionValues = new ExtraFieldValue('session');
1990
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1991
                    $sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1992
1993
                    if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
1994
                        $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
1995
                        $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1996
                        $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
1997
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1998
                    } else {
1999
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
2000
                    }
2001
                } else {
2002
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
2003
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
2004
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
2005
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
2006
2007
                    $metaDescription = api_get_setting('meta_description');
2008
                    if (!empty($metaDescription)) {
2009
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
2010
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
2011
                    }
2012
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
2013
                }
2014
            }
2015
        }
2016
2017
        $this->assign('social_meta', $socialMeta);
2018
2019
        return true;
2020
    }
2021
2022
    /**
2023
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
2024
     *
2025
     * @param string $imageAlt The alt attribute for the image
2026
     *
2027
     * @return string The meta image HTML tag, or empty
2028
     */
2029
    private function getMetaPortalImagePath($imageAlt = '')
2030
    {
2031
        // Load portal meta image if defined
2032
        $metaImage = api_get_setting('meta_image_path');
2033
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
2034
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
2035
        $portalImageMeta = '';
2036
        if (!empty($metaImage)) {
2037
            if (is_file($metaImageSysPath)) {
2038
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
2039
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
2040
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
2041
            }
2042
        } else {
2043
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
2044
            if (!empty($logo)) {
2045
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
2046
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
2047
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
2048
            }
2049
        }
2050
2051
        return $portalImageMeta;
2052
    }
2053
}
2054