Passed
Push — master ( 03bb22...dedfe2 )
by Julito
07:39
created

Template::displayTwoColTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
7
use Chamilo\CoreBundle\Entity\User;
8
use Chamilo\CoreBundle\Framework\Container;
9
use Symfony\Component\HttpFoundation\Response;
10
11
/**
12
 * Class Template.
13
 *
14
 * @author Julio Montoya <[email protected]>
15
 *
16
 * @todo better organization of the class, methods and variables
17
 */
18
class Template
19
{
20
    /**
21
     * The Template folder name see main/template.
22
     *
23
     * @var string
24
     */
25
    public $templateFolder = 'default';
26
27
    /**
28
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
29
     * This variable is set from the database.
30
     *
31
     * @var string
32
     */
33
    public $theme = '';
34
35
    /**
36
     * @var string
37
     */
38
    public $preview_theme = '';
39
    public $title = null;
40
    public $show_header;
41
    public $show_footer;
42
    public $help;
43
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
44
    public $show_learnpath = false; // This is a learnpath section or not?
45
    public $plugin = null;
46
    public $course_id = null;
47
    public $user_is_logged_in = false;
48
    public $twig = null;
49
50
    /* Loads chamilo plugins */
51
    public $load_plugins = false;
52
    public $params = [];
53
    public $force_plugin_load = false;
54
    public $responseCode = 0;
55
    private $themeDir;
56
57
    /**
58
     * @param string $title
59
     * @param bool   $show_header
60
     * @param bool   $show_footer
61
     * @param bool   $show_learnpath
62
     * @param bool   $hide_global_chat
63
     * @param bool   $load_plugins
64
     * @param int    $responseCode
65
     * @param bool   $sendHeaders      send http headers or not
66
     */
67
    public function __construct(
68
        $title = '',
69
        $show_header = true,
70
        $show_footer = true,
71
        $show_learnpath = false,
72
        $hide_global_chat = false,
73
        $load_plugins = true,
74
        $sendHeaders = true,
75
        $responseCode = 0
76
    ) {
77
        // Page title
78
        $this->title = $title;
79
        global $interbreadcrumb;
80
        $interbreadcrumb[] = ['url' => '#', 'name' => $title];
81
        $this->show_learnpath = $show_learnpath;
82
        //$this->setResponseCode($responseCode);
83
84
        if (empty($this->show_learnpath)) {
85
            $origin = api_get_origin();
86
            if ('learnpath' === $origin) {
87
                $this->show_learnpath = true;
88
                $show_footer = false;
89
                $show_header = false;
90
            }
91
        }
92
        $this->hide_global_chat = $hide_global_chat;
93
        $this->load_plugins = $load_plugins;
94
95
        /*$template_paths = [
96
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
97
            api_get_path(SYS_CODE_PATH).'template', //template folder
98
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
99
            api_get_path(SYS_PATH).'src/ThemeBundle/Resources/views',
100
        ];*/
101
102
        $this->twig = Container::getTwig();
103
104
        // Setting system variables
105
        //$this->set_system_parameters();
106
107
        // Setting user variables
108
        //$this->set_user_parameters();
109
110
        // Setting course variables
111
        //$this->set_course_parameters();
112
113
        // Setting administrator variables
114
        //$this->setAdministratorParams();
115
        //$this->setCSSEditor();
116
117
        // Header and footer are showed by default
118
        //$this->set_footer($show_footer);
119
        //$this->set_header($show_header);
120
121
        //$this->set_header_parameters($sendHeaders);
122
        //$this->set_footer_parameters();
123
124
        $defaultStyle = api_get_setting('display.default_template');
125
        if (!empty($defaultStyle)) {
126
            $this->templateFolder = $defaultStyle;
0 ignored issues
show
Documentation Bug introduced by
It seems like $defaultStyle can also be of type array. 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...
127
        }
128
    }
129
130
    /**
131
     * @param string $helpInput
132
     */
133
    public function setHelp($helpInput = null)
134
    {
135
        if (!empty($helpInput)) {
136
            $help = $helpInput;
137
        } else {
138
            $help = $this->help;
139
        }
140
141
        $content = '';
142
        if ('true' == api_get_setting('enable_help_link')) {
143
            if (!empty($help)) {
144
                $help = Security::remove_XSS($help);
145
                $content = '<div class="help">';
146
                $content .= Display::url(
147
                    Display::return_icon('help.png', get_lang('Help'), null, ICON_SIZE_LARGE),
148
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
149
                    [
150
                        'class' => 'ajax',
151
                        'data-title' => get_lang('Help'),
152
                    ]
153
                );
154
                $content .= '</div>';
155
            }
156
        }
157
        $this->assign('help_content', $content);
158
    }
159
160
    /**
161
     * Use template system to parse the actions menu.
162
     *
163
     * @todo finish it!
164
     */
165
    public function set_actions($actions)
166
    {
167
        $action_string = '';
168
        if (!empty($actions)) {
169
            foreach ($actions as $action) {
170
                $action_string .= $action;
171
            }
172
        }
173
        $this->assign('actions', $actions);
174
    }
175
176
    /**
177
     * Render the template.
178
     *
179
     * @param string $template The template path
180
     */
181
    public function display($template)
182
    {
183
        $template = str_replace('tpl', 'html.twig', $template);
184
        $templateFile = api_get_path(SYS_CODE_PATH).'template/'.$template;
185
186
        $this->loadLegacyParams();
187
188
        if (!file_exists($templateFile)) {
189
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
190
            echo $e->getMessage();
191
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
192
        }
193
194
        $this->setVueParams($this->params);
195
        $this->returnResponse($this->params, $template);
196
    }
197
198
    /**
199
     * @param string $template
200
     *
201
     * @throws \Twig\Error\Error
202
     */
203
    public function displayTemplate($template)
204
    {
205
        $this->loadLegacyParams();
206
        $this->returnResponse($this->params, $template);
207
    }
208
209
    /**
210
     * Shortcut to display a 1 col layout (index.php).
211
     * */
212
    public function display_one_col_template()
213
    {
214
        $this->loadLegacyParams();
215
        $template = '@ChamiloCore/Layout/layout_one_col.html.twig';
216
        $origin = api_get_origin();
217
        if ('learnpath' === $origin) {
218
            $template = '@ChamiloCore/Layout/no_layout.html.twig';
219
        }
220
        $this->setVueParams($this->params);
221
        $this->returnResponse($this->params, $template);
222
    }
223
224
    public function displayTwoColTemplate()
225
    {
226
        $this->loadLegacyParams();
227
        $template = '@ChamiloCore/Layout/layout_two_col.html.twig';
228
        $this->setVueParams($this->params);
229
        $this->returnResponse($this->params, $template);
230
    }
231
232
    /**
233
     * Displays an empty template.
234
     */
235
    public function display_blank_template()
236
    {
237
        $this->loadLegacyParams();
238
        $template = '@ChamiloCore/Layout/blank.html.twig';
239
        $this->returnResponse($this->params, $template);
240
    }
241
242
    /**
243
     * Displays an empty template.
244
     */
245
    public function displayBlankTemplateNoHeader()
246
    {
247
        $this->loadLegacyParams();
248
        $template = '@ChamiloCore/Layout/blank_no_header.html.twig';
249
        $this->returnResponse($this->params, $template);
250
    }
251
252
    /**
253
     * Displays an empty template.
254
     */
255
    public function display_no_layout_template()
256
    {
257
        $this->loadLegacyParams();
258
        $template = '@ChamiloCore/Layout/no_layout.html.twig';
259
        $this->returnResponse($this->params, $template);
260
    }
261
262
    /**
263
     * Displays an empty template.
264
     */
265
    public function displaySkillLayout()
266
    {
267
        $this->loadLegacyParams();
268
        $template = '@ChamiloCore/Layout/skill_layout.html.twig';
269
        $this->returnResponse($this->params, $template);
270
    }
271
272
    /**
273
     * return true if toolbar has to be displayed for user.
274
     *
275
     * @return bool
276
     */
277
    public static function isToolBarDisplayedForUser()
278
    {
279
        //Toolbar
280
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
281
        $show_toolbar = false;
282
283
        switch ($show_admin_toolbar) {
284
            case 'do_not_show':
285
                break;
286
            case 'show_to_admin':
287
                if (api_is_platform_admin()) {
288
                    $show_toolbar = true;
289
                }
290
                break;
291
            case 'show_to_admin_and_teachers':
292
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
293
                    $show_toolbar = true;
294
                }
295
                break;
296
            case 'show_to_all':
297
                $show_toolbar = true;
298
                break;
299
        }
300
301
        return $show_toolbar;
302
    }
303
304
    /**
305
     * Sets the header visibility.
306
     *
307
     * @param bool true if we show the header
308
     */
309
    public function set_header($status)
310
    {
311
        $this->show_header = $status;
312
        $this->assign('show_header', $status);
313
314
        $show_toolbar = 0;
315
316
        if (self::isToolBarDisplayedForUser()) {
317
            $show_toolbar = 1;
318
        }
319
320
        $this->assign('show_toolbar', $show_toolbar);
321
322
        // Only if course is available
323
        $courseToolBar = '';
324
        $show_course_navigation_menu = '';
325
        if (!empty($this->course_id) && $this->user_is_logged_in) {
326
            if ('false' !== api_get_setting('show_toolshortcuts')) {
327
                // Course toolbar
328
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
329
            }
330
            if ('false' !== api_get_setting('show_navigation_menu')) {
331
                //Course toolbar
332
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
333
            }
334
        }
335
        $this->assign('show_course_shortcut', $courseToolBar);
336
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
337
    }
338
339
    /**
340
     * Returns the sub-folder and filename for the given tpl file.
341
     *
342
     * If template not found in overrides/ or custom template folder, the default template will be used.
343
     *
344
     * @param string $name
345
     *
346
     * @return string
347
     */
348
    public static function findTemplateFilePath($name)
349
    {
350
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
351
352
        // Check if the tpl file is present in the main/template/overrides/ dir
353
        // Overrides is a special directory meant for temporary template
354
        // customization. It must be taken into account before anything else
355
        if (is_readable($sysTemplatePath."overrides/$name")) {
356
            return "overrides/$name";
357
        }
358
359
        $defaultFolder = api_get_configuration_value('default_template');
360
361
        // If a template folder has been manually defined, search for the right
362
        // file, and if not found, go for the same file in the default template
363
        if ($defaultFolder && 'default' != $defaultFolder) {
364
            // Avoid missing template error, use the default file.
365
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
366
                return "$defaultFolder/$name";
367
            }
368
        }
369
370
        $name = str_replace('tpl', 'html.twig', $name);
371
372
        return "default/$name";
373
    }
374
375
    /**
376
     * Call non-static for Template::findTemplateFilePath.
377
     *
378
     * @see Template::findTemplateFilePath()
379
     *
380
     * @param string $name
381
     *
382
     * @return string
383
     */
384
    public function get_template($name)
385
    {
386
        return api_find_template($name);
387
    }
388
389
    /**
390
     * Get CSS themes sub-directory.
391
     *
392
     * @param string $theme
393
     *
394
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
395
     */
396
    public static function getThemeDir($theme)
397
    {
398
        $themeDir = 'themes/'.$theme.'/';
399
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
400
        if (!empty($virtualTheme)) {
401
            $virtualThemeList = api_get_themes(true);
402
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
403
            if ($isVirtualTheme) {
404
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
405
            }
406
        }
407
408
        return $themeDir;
409
    }
410
411
    /**
412
     * Set legacy twig globals in order to be hook in the LegacyListener.php.
413
     *
414
     * @return array
415
     */
416
    public static function getGlobals()
417
    {
418
        return [
419
            '_s' => [
420
                'software_name' => api_get_configuration_value('software_name'),
421
                'system_version' => api_get_configuration_value('system_version'),
422
                'site_name' => api_get_setting('siteName'),
423
                'institution' => api_get_setting('Institution'),
424
                'gamification_mode' => api_get_setting('gamification_mode'),
425
            ],
426
            'template' => 'default', // @todo setup template folder in config.yml;
427
        ];
428
    }
429
430
    /**
431
     * Set theme, include mainstream CSS files.
432
     *
433
     * @deprecated
434
     * @see setCssCustomFiles() for additional CSS sheets
435
     */
436
    public function setCssFiles()
437
    {
438
        global $disable_js_and_css_files;
439
        $css = [];
440
441
        // Default CSS Bootstrap
442
        $bowerCSSFiles = [
443
            'fontawesome/css/font-awesome.min.css',
444
            'jquery-ui/themes/smoothness/theme.css',
445
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
446
            'mediaelement/build/mediaelementplayer.min.css',
447
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
448
            'bootstrap/dist/css/bootstrap.min.css',
449
            'jquery.scrollbar/jquery.scrollbar.css',
450
            //'bootstrap-daterangepicker/daterangepicker.css',
451
            'bootstrap-select/dist/css/bootstrap-select.min.css',
452
            'select2/dist/css/select2.min.css',
453
            'flag-icon-css/css/flag-icon.min.css',
454
            'mediaelement/plugins/vrview/vrview.css',
455
        ];
456
457
        $features = api_get_configuration_value('video_features');
458
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen', 'vrview'];
459
460
        if (!empty($features) && isset($features['features'])) {
461
            foreach ($features['features'] as $feature) {
462
                if ('vrview' === $feature) {
463
                    continue;
464
                }
465
                $bowerCSSFiles[] = "mediaelement/plugins/$feature/$feature.css";
466
                $defaultFeatures[] = $feature;
467
            }
468
        }
469
470
        foreach ($bowerCSSFiles as $file) {
471
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
472
        }
473
474
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
475
476
        if (api_is_global_chat_enabled()) {
477
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
478
        }
479
        $css_file_to_string = '';
480
        foreach ($css as $file) {
481
            $css_file_to_string .= api_get_css($file);
482
        }
483
484
        if (!$disable_js_and_css_files) {
485
            $this->assign('css_static_file_to_string', $css_file_to_string);
486
        }
487
488
        $defaultFeatures = implode("','", $defaultFeatures);
489
        $this->assign('video_features', $defaultFeatures);
490
    }
491
492
    /**
493
     * Prepare custom CSS to be added at the very end of the <head> section.
494
     *
495
     * @see setCssFiles() for the mainstream CSS files
496
     */
497
    public function setCssCustomFiles()
498
    {
499
        global $disable_js_and_css_files;
500
        $css = [];
501
        if ($this->show_learnpath) {
502
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
503
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
504
            }
505
        }
506
507
        $css_file_to_string = '';
508
        foreach ($css as $file) {
509
            $css_file_to_string .= api_get_css($file);
510
        }
511
512
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
513
        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...
514
            //hack in order to fix the actions buttons
515
            $css_file_to_string .= '<style>
516
                .td_actions a {
517
                    float:left;
518
                    width:100%;
519
                }
520
                .forum_message_left a {
521
                    float:left;
522
                    width:100%;
523
                }
524
                </style>';
525
        }
526
527
        $navigator_info = api_get_navigator();
528
        if ('Internet Explorer' == $navigator_info['name'] && '6' == $navigator_info['version']) {
529
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
530
        }
531
532
        if (!$disable_js_and_css_files) {
533
            $this->assign('css_custom_file_to_string', $css_file_to_string);
534
535
            $style_print = '';
536
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
537
                $style_print = api_get_css(
538
                    api_get_path(WEB_CSS_PATH).$this->theme.'/print.css',
539
                    'print'
540
                );
541
            }
542
            $this->assign('css_style_print', $style_print);
543
        }
544
545
        // Logo
546
        $logo = return_logo($this->theme);
547
        $logoPdf = return_logo($this->theme, false);
548
        $this->assign('logo', $logo);
549
        $this->assign('logo_pdf', $logoPdf);
550
        $this->assign('show_media_element', 1);
551
    }
552
553
    /**
554
     * Declare and define the template variable that will be used to load
555
     * javascript libraries in the header.
556
     */
557
    public function set_js_files()
558
    {
559
        global $disable_js_and_css_files, $htmlHeadXtra;
560
        $isoCode = api_get_language_isocode();
561
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
562
563
        if ('en' == $isoCode) {
564
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
565
        }
566
        // JS files
567
        $js_files = [
568
            'chosen/chosen.jquery.min.js',
569
        ];
570
571
        $viewBySession = 'true' === api_get_setting('my_courses_view_by_session');
572
573
        if (api_is_global_chat_enabled() || $viewBySession) {
574
            // Do not include the global chat in LP
575
            if (false == $this->show_learnpath &&
576
                true == $this->show_footer &&
577
                false == $this->hide_global_chat
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...
578
            ) {
579
                $js_files[] = 'chat/js/chat.js';
580
            }
581
        }
582
583
        if ('true' === api_get_setting('accessibility_font_resize')) {
584
            $js_files[] = 'fontresize.js';
585
        }
586
587
        $js_file_to_string = '';
588
        $bowerJsFiles = [
589
            'modernizr/modernizr.js',
590
            'jquery/query.min.js',
591
            'bootstrap/dist/js/bootstrap.min.js',
592
            'jquery-ui/jquery-ui.min.js',
593
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
594
            'moment/min/moment-with-locales.js',
595
            //'bootstrap-daterangepicker/daterangepicker.js',
596
            'jquery-timeago/jquery.timeago.js',
597
            'mediaelement/mediaelement-and-player.min.js',
598
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
599
            'image-map-resizer/js/imageMapResizer.min.js',
600
            'jquery.scrollbar/jquery.scrollbar.min.js',
601
            //'readmore-js/readmore.min.js',
602
            'bootstrap-select/dist/js/bootstrap-select.min.js',
603
            $selectLink,
604
            'select2/dist/js/select2.min.js',
605
            "select2/dist/js/i18n/$isoCode.js",
606
            'mediaelement/plugins/vrview/vrview.js',
607
        ];
608
609
        $features = api_get_configuration_value('video_features');
610
        if (!empty($features) && isset($features['features'])) {
611
            foreach ($features['features'] as $feature) {
612
                if ('vrview' === $feature) {
613
                    continue;
614
                }
615
                $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js";
616
            }
617
        }
618
619
        if (CHAMILO_LOAD_WYSIWYG === true) {
620
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
621
        }
622
623
        if ('true' === api_get_setting('include_asciimathml_script')) {
624
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
625
        }
626
627
        if ('en' != $isoCode) {
628
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
629
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
630
        }
631
632
        foreach ($bowerJsFiles as $file) {
633
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
634
        }
635
636
        foreach ($js_files as $file) {
637
            //$js_file_to_string .= api_get_js($file);
638
        }
639
640
        // Loading email_editor js
641
        if (!api_is_anonymous() && 'true' == api_get_setting('allow_email_editor')) {
642
            $template = $this->get_template('mail_editor/email_link.js.tpl');
643
            $js_file_to_string .= $this->fetch($template);
644
        }
645
646
        if (!$disable_js_and_css_files) {
647
            $this->assign('js_file_to_string', $js_file_to_string);
648
            $extraHeaders = '';
649
            //$extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
650
            //Adding jquery ui by default
651
            $extraHeaders .= api_get_jquery_ui_js();
652
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
653
                foreach ($htmlHeadXtra as &$this_html_head) {
654
                    $extraHeaders .= $this_html_head."\n";
655
                }
656
            }
657
658
            $ajax = api_get_path(WEB_AJAX_PATH);
659
            $courseId = api_get_course_id();
660
            if (empty($courseId)) {
661
                $courseLogoutCode = '
662
                <script>
663
                function courseLogout() {
664
                }
665
                </script>';
666
            } else {
667
                $courseLogoutCode = "
668
                <script>
669
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
670
                function courseLogout() {
671
                    $.ajax({
672
                        async : false,
673
                        url: logOutUrl,
674
                        success: function (data) {
675
                            return 1;
676
                        }
677
                    });
678
                }
679
                </script>";
680
            }
681
682
            $extraHeaders .= $courseLogoutCode;
683
            $this->assign('extra_headers', $extraHeaders);
684
        }
685
    }
686
687
    public static function setVueParams(&$params)
688
    {
689
        $params['is_authenticated'] = !api_is_anonymous();
690
        /*$user = api_get_user_entity(api_get_user_id());
691
        $encoded = '';
692
        if ($user) {
693
            $encoded = json_encode($user);
694
        }
695
        $params['user'] = $encoded;*/
696
        $params['from_vue'] = isset($_REQUEST['from_vue']) ? 1 : 0;
697
    }
698
699
    /**
700
     * @param array  $params
701
     * @param string $template
702
     *
703
     * @throws \Twig\Error\Error
704
     */
705
    public function returnResponse($params, $template)
706
    {
707
        $response = new Response();
708
        $content = Container::getTwig()->render($template, $params);
709
        $response->setContent($content);
710
        $response->send();
711
    }
712
713
    /**
714
     * Special function to declare last-minute JS libraries which depend on
715
     * other things to be declared first. In particular, it might be useful
716
     * under IE9 with compatibility mode, which for some reason is getting
717
     * upset when a variable is used in a function (even if not used yet)
718
     * when this variable hasn't been defined yet.
719
     */
720
    public function set_js_files_post()
721
    {
722
        global $disable_js_and_css_files;
723
        $js_files = [];
724
        if (api_is_global_chat_enabled()) {
725
            //Do not include the global chat in LP
726
            if (false == $this->show_learnpath && true == $this->show_footer && false == $this->hide_global_chat) {
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...
727
                $js_files[] = 'chat/js/chat.js';
728
            }
729
        }
730
        $js_file_to_string = '';
731
        foreach ($js_files as $js_file) {
732
            $js_file_to_string .= api_get_js($js_file);
733
        }
734
        if (!$disable_js_and_css_files) {
735
            $this->assign('js_file_to_string_post', $js_file_to_string);
736
        }
737
    }
738
739
    /**
740
     * @param string $theme
741
     *
742
     * @return string
743
     */
744
    public static function getPortalIcon($theme)
745
    {
746
        // Default root chamilo favicon
747
        $icon = 'favicon.ico';
748
749
        // Added to verify if in the current Chamilo Theme exist a favicon
750
        $themeUrl = api_get_path(SYS_CSS_PATH).'themes/'.$theme.'/images/';
751
752
        // If exist pick the current chamilo theme favicon.
753
        if (is_file($themeUrl.'favicon.ico')) {
754
            $icon = 'build/css/themes/'.$theme.'/images/favicon.ico';
755
        }
756
757
        return $icon;
758
    }
759
760
    /**
761
     * Show footer js template.
762
     */
763
    public function show_footer_js_template()
764
    {
765
        $tpl = $this->get_template('layout/footer.js.tpl');
766
        $this->display($tpl);
767
    }
768
769
    /**
770
     * @param string $template
771
     *
772
     * @return string
773
     */
774
    public function fetch($template = null)
775
    {
776
        return $this->twig->render($template, $this->params);
777
    }
778
779
    /**
780
     * @param string $variable
781
     * @param mixed  $value
782
     */
783
    public function assign($variable, $value = '')
784
    {
785
        $this->params[$variable] = $value;
786
    }
787
788
    /**
789
     * Adds a body class for login pages.
790
     */
791
    public function setLoginBodyClass()
792
    {
793
        $this->assign('login_class', 'section-login');
794
    }
795
796
    /**
797
     * The theme that will be used if the database is not working.
798
     *
799
     * @return string
800
     */
801
    public static function getThemeFallback()
802
    {
803
        $theme = api_get_configuration_value('theme_fallback');
804
        if (empty($theme)) {
805
            $theme = 'chamilo';
806
        }
807
808
        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...
809
    }
810
811
    /**
812
     * @return string
813
     */
814
    public function handleLoginFailed()
815
    {
816
        $message = get_lang('Login failed - incorrect login or password.');
817
818
        if (!isset($_GET['error'])) {
819
            if (api_is_self_registration_allowed()) {
820
                $message = get_lang('Login failed - if you are not registered, you can do so using the <a href=claroline/auth/inscription.php>registration form</a>');
821
            }
822
        } else {
823
            switch ($_GET['error']) {
824
                case '':
825
                    if (api_is_self_registration_allowed()) {
826
                        $message = get_lang('Login failed - if you are not registered, you can do so using the <a href=claroline/auth/inscription.php>registration form</a>');
827
                    }
828
                    break;
829
                case 'account_expired':
830
                    $message = get_lang('Account expired');
831
                    break;
832
                case 'account_inactive':
833
                    $message = get_lang('Account inactive');
834
835
                    if ('confirmation' === api_get_setting('allow_registration')) {
836
                        $message = get_lang('Your account is inactive because you have not confirmed it yet. Check your email and follow the instructions or click the following link to resend the email').PHP_EOL;
837
                        $message .= Display::url(
838
                            get_lang('Send confirmation mail again'),
839
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
840
                            ['class' => 'alert-link']
841
                        );
842
                    }
843
                    break;
844
                case 'user_password_incorrect':
845
                    $message = get_lang('Login failed - incorrect login or password.');
846
                    break;
847
                case 'access_url_inactive':
848
                    $message = get_lang('Account inactive for this URL');
849
                    break;
850
                case 'wrong_captcha':
851
                    $message = get_lang('The text you entered doesn\'t match the picture.');
852
                    break;
853
                case 'blocked_by_captcha':
854
                    $message = get_lang('Account blocked by captcha.');
855
                    break;
856
                case 'multiple_connection_not_allowed':
857
                    $message = get_lang('This user is already logged in');
858
                    break;
859
            }
860
        }
861
862
        return Display::return_message($message, 'error', false);
863
    }
864
865
    /**
866
     * @return string
867
     */
868
    public function displayLoginForm()
869
    {
870
        $form = new FormValidator(
871
            'form-login',
872
            'POST',
873
            api_get_path(WEB_PUBLIC_PATH).'login_check',
874
            null,
875
            null,
876
            FormValidator::LAYOUT_BOX_NO_LABEL
877
        );
878
        $params = [
879
            'id' => '_username',
880
            'autofocus' => 'autofocus',
881
            'icon' => 'user fa-fw',
882
            'placeholder' => get_lang('Username'),
883
        ];
884
885
        // Avoid showing the autocapitalize option if the browser doesn't
886
        // support it: this attribute is against the HTML5 standard
887
        /*$browserAutoCapitalize = false;
888
        if (api_browser_support('autocapitalize')) {
889
            $browserAutoCapitalize = false;
890
            $params['autocapitalize'] = 'none';
891
        }*/
892
        $form->addText(
893
            '_username',
894
            get_lang('Username'),
895
            true,
896
            $params
897
        );
898
        $params = [
899
            'id' => '_password',
900
            'icon' => 'lock fa-fw',
901
            'placeholder' => get_lang('Pass'),
902
        ];
903
        /*if ($browserAutoCapitalize) {
904
            $params['autocapitalize'] = 'none';
905
        }*/
906
        $form->addElement(
907
            'password',
908
            '_password',
909
            get_lang('Pass'),
910
            $params
911
        );
912
913
        $token = Chamilo\CoreBundle\Framework\Container::$container->get('security.csrf.token_manager')->getToken('authenticate');
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

913
        $token = Chamilo\CoreBundle\Framework\Container::$container->/** @scrutinizer ignore-call */ get('security.csrf.token_manager')->getToken('authenticate');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
914
        $form->addHidden('_csrf_token', $token->getValue());
915
916
        // Captcha
917
        $captcha = api_get_setting('allow_captcha');
918
        $allowCaptcha = 'true' === $captcha;
919
920
        if ($allowCaptcha) {
921
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
922
            if ($useCaptcha) {
923
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
924
                $options = [
925
                    'width' => 250,
926
                    'height' => 90,
927
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
928
                    'sessionVar' => basename(__FILE__, '.php'),
929
                    'imageOptions' => [
930
                        'font_size' => 20,
931
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
932
                        'font_file' => 'OpenSans-Regular.ttf',
933
                        //'output' => 'gif'
934
                    ],
935
                ];
936
937
                // Minimum options using all defaults (including defaults for Image_Text):
938
                //$options = array('callback' => 'qfcaptcha_image.php');
939
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
940
                $form->addHtml(get_lang('Click on the image to load a new one.'));
941
942
                $form->addElement(
943
                    'text',
944
                    'captcha',
945
                    get_lang('Enter the letters you see.')
946
                );
947
                $form->addRule(
948
                    'captcha',
949
                    get_lang('Enter the characters you see on the image'),
950
                    'required',
951
                    null,
952
                    'client'
953
                );
954
                $form->addRule(
955
                    'captcha',
956
                    get_lang('The text you entered doesn\'t match the picture.'),
957
                    'CAPTCHA',
958
                    $captcha_question
959
                );
960
            }
961
        }
962
963
        $form->addButton(
964
            'submitAuth',
965
            get_lang('Login'),
966
            null,
967
            'primary',
968
            null,
969
            'btn-block'
970
        );
971
972
        $html = $form->returnForm();
973
974
        return $html;
975
    }
976
977
    /**
978
     * Returns the tutors names for the current course in session
979
     * Function to use in Twig templates.
980
     *
981
     * @return string
982
     */
983
    public static function returnTutorsNames()
984
    {
985
        $em = Database::getManager();
986
        $tutors = $em
987
            ->createQuery('
988
                SELECT u FROM ChamiloCoreBundle:User u
989
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
990
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
991
            ')
992
            ->setParameters([
993
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
994
                'session' => api_get_session_id(),
995
                'course' => api_get_course_int_id(),
996
            ])
997
            ->getResult();
998
999
        $names = [];
1000
1001
        /** @var User $tutor */
1002
        foreach ($tutors as $tutor) {
1003
            $names[] = UserManager::formatUserFullName($tutor);
1004
        }
1005
1006
        return implode(CourseManager::USER_SEPARATOR, $names);
1007
    }
1008
1009
    /*s
1010
     * Returns the teachers name for the current course
1011
     * Function to use in Twig templates
1012
     * @return string
1013
     */
1014
    public static function returnTeachersNames()
1015
    {
1016
        $em = Database::getManager();
1017
        $teachers = $em
1018
            ->createQuery('
1019
                SELECT u FROM ChamiloCoreBundle:User u
1020
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1021
                WHERE cu.status = :teacher_status AND cu.course = :course
1022
            ')
1023
            ->setParameters([
1024
                'teacher_status' => User::COURSE_MANAGER,
1025
                'course' => api_get_course_int_id(),
1026
            ])
1027
            ->getResult();
1028
1029
        $names = [];
1030
1031
        /** @var User $teacher */
1032
        foreach ($teachers as $teacher) {
1033
            $names[] = UserManager::formatUserFullName($teacher);
1034
        }
1035
1036
        return implode(CourseManager::USER_SEPARATOR, $names);
1037
    }
1038
1039
    /**
1040
     * @param int $code
1041
     */
1042
    public function setResponseCode($code)
1043
    {
1044
        $this->responseCode = $code;
1045
    }
1046
1047
    public function getResponseCode()
1048
    {
1049
        return $this->responseCode;
1050
    }
1051
1052
    /**
1053
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1054
     *
1055
     * @return bool Always return true because there is always a string, even if empty
1056
     */
1057
    public function assignBugNotification()
1058
    {
1059
        //@todo move this in the template
1060
        $rightFloatMenu = '';
1061
        $iconBug = Display::return_icon(
1062
            'bug.png',
1063
            get_lang('Report a bug'),
1064
            [],
1065
            ICON_SIZE_LARGE
1066
        );
1067
        if ('true' === api_get_setting('show_link_bug_notification') && $this->user_is_logged_in) {
1068
            $rightFloatMenu = '<div class="report">
1069
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1070
                    '.$iconBug.'
1071
                </a>
1072
		        </div>';
1073
        }
1074
1075
        if ('true' === api_get_setting('show_link_ticket_notification') &&
1076
            $this->user_is_logged_in
1077
        ) {
1078
            // by default is project_id = 1
1079
            $defaultProjectId = 1;
1080
            $iconTicket = Display::return_icon(
1081
                'help.png',
1082
                get_lang('Ticket'),
1083
                [],
1084
                ICON_SIZE_LARGE
1085
            );
1086
            $courseInfo = api_get_course_info();
1087
            $courseParams = '';
1088
            if (!empty($courseInfo)) {
1089
                $courseParams = api_get_cidreq();
1090
            }
1091
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams;
1092
1093
            $allow = TicketManager::userIsAllowInProject(api_get_user_info(), $defaultProjectId);
1094
1095
            if ($allow) {
1096
                $rightFloatMenu .= '<div class="help">
1097
                    <a href="'.$url.'" target="_blank">
1098
                        '.$iconTicket.'
1099
                    </a>
1100
                </div>';
1101
            }
1102
        }
1103
1104
        $this->assign('bug_notification', $rightFloatMenu);
1105
1106
        return true;
1107
    }
1108
1109
    /**
1110
     * Load legacy params.
1111
     */
1112
    private function loadLegacyParams()
1113
    {
1114
        // Set legacy breadcrumb
1115
        global $interbreadcrumb;
1116
1117
        $courseInfo = api_get_course_info();
1118
        if (!empty($courseInfo)) {
1119
            $url = $courseInfo['course_public_url'];
1120
            $sessionId = api_get_session_id();
1121
            if (!empty($sessionId)) {
1122
                $url .= '?sid='.$sessionId;
1123
            }
1124
            array_unshift(
1125
                $interbreadcrumb,
1126
                ['name' => $courseInfo['title'], 'url' => $url]
1127
            );
1128
        }
1129
1130
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
1131
1132
        global $htmlHeadXtra;
1133
        $this->params['legacy_javascript'] = $htmlHeadXtra;
1134
    }
1135
1136
    /**
1137
     * Prepare the _c array for template files. The _c array contains
1138
     * information about the current course.
1139
     */
1140
    private function set_course_parameters()
1141
    {
1142
        //Setting course id
1143
        $course = api_get_course_info();
1144
        if (empty($course)) {
1145
            $this->assign('course_is_set', false);
1146
1147
            return;
1148
        }
1149
        $this->assign('course_is_set', true);
1150
        $this->course_id = $course['id'];
1151
        $_c = [
1152
            'id' => $course['real_id'],
1153
            'code' => $course['code'],
1154
            'title' => $course['name'],
1155
            'visibility' => $course['visibility'],
1156
            'language' => $course['language'],
1157
            'directory' => $course['directory'],
1158
            'session_id' => api_get_session_id(),
1159
            'user_is_teacher' => api_is_course_admin(),
1160
            'student_view' => (!empty($_GET['isStudentView']) && 'true' == $_GET['isStudentView']),
1161
        ];
1162
        $this->assign('course_code', $course['code']);
1163
        $this->assign('_c', $_c);
1164
    }
1165
1166
    /**
1167
     * Prepare the _u array for template files. The _u array contains
1168
     * information about the current user, as returned by
1169
     * api_get_user_info().
1170
     */
1171
    private function set_user_parameters()
1172
    {
1173
        $user_info = [];
1174
        $user_info['logged'] = 0;
1175
        $this->user_is_logged_in = false;
1176
        if (!api_is_anonymous()) {
1177
            $user_info = api_get_user_info(api_get_user_id(), true);
1178
            $user_info['logged'] = 1;
1179
1180
            $user_info['is_admin'] = 0;
1181
            if (api_is_platform_admin()) {
1182
                $user_info['is_admin'] = 1;
1183
            }
1184
1185
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1186
            $this->user_is_logged_in = true;
1187
        }
1188
        // Setting the $_u array that could be use in any template
1189
        $this->assign('_u', $user_info);
1190
    }
1191
1192
    /**
1193
     * Set header parameters.
1194
     *
1195
     * @deprecated
1196
     *
1197
     * @param bool $sendHeaders send headers
1198
     */
1199
    private function set_header_parameters($sendHeaders)
1200
    {
1201
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1202
        $_course = api_get_course_info();
1203
        $nameTools = $this->title;
1204
        $navigation = return_navigation_array();
1205
        $this->menu_navigation = $navigation['menu_navigation'];
1206
1207
        $this->assign('system_charset', api_get_system_encoding());
1208
1209
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1210
            foreach ($httpHeadXtra as &$thisHttpHead) {
1211
                //header($thisHttpHead);
1212
            }
1213
        }
1214
1215
        $this->assign(
1216
            'online_button',
1217
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
1218
        );
1219
        $this->assign(
1220
            'offline_button',
1221
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
1222
        );
1223
1224
        // Get language iso-code for this page - ignore errors
1225
        $this->assign('document_language', api_get_language_isocode());
1226
1227
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1228
1229
        $title_list = [];
1230
1231
        $title_list[] = api_get_setting('Institution');
1232
        $title_list[] = api_get_setting('siteName');
1233
1234
        if (!empty($course_title)) {
1235
            $title_list[] = $course_title;
1236
        }
1237
        if ('' != $nameTools) {
1238
            $title_list[] = $nameTools;
1239
        }
1240
1241
        $title_string = '';
1242
        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...
1243
            $title_string .= $title_list[$i];
1244
            if (isset($title_list[$i + 1])) {
1245
                $item = trim($title_list[$i + 1]);
1246
                if (!empty($item)) {
1247
                    $title_string .= ' - ';
1248
                }
1249
            }
1250
        }
1251
1252
        $this->assign('title_string', $title_string);
1253
1254
        // Setting the theme and CSS files
1255
        //$this->setCssFiles();
1256
        $this->set_js_files();
1257
        $this->setCssCustomFiles();
1258
1259
        /*$browser = api_browser_support('check_browser');
1260
        if ('Internet Explorer' == $browser[0] && $browser[1] >= '11') {
1261
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1262
            $this->assign('browser_specific_head', $browser_head);
1263
        }*/
1264
1265
        // Implementation of prefetch.
1266
        // See http://cdn.chamilo.org/main/img/online.png for details
1267
        $prefetch = '';
1268
        if (!empty($_configuration['cdn_enable'])) {
1269
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1270
            foreach ($_configuration['cdn'] as $host => $exts) {
1271
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1272
            }
1273
        }
1274
1275
        $this->assign('prefetch', $prefetch);
1276
        $this->assign('text_direction', api_get_text_direction());
1277
        $this->assign('section_name', 'section-'.$this_section);
1278
        $this->assignFavIcon();
1279
        $this->setHelp();
1280
1281
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1282
1283
        $this->assignAccessibilityBlock(); //Prepare the 'accessibility' var for the template
1284
1285
        // Preparing values for the menu
1286
1287
        // Logout link
1288
        $hideLogout = api_get_setting('hide_logout_button');
1289
        if ('true' === $hideLogout) {
1290
            $this->assign('logout_link', null);
1291
        } else {
1292
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1293
        }
1294
1295
        // Profile link
1296
        if ('true' == api_get_setting('allow_social_tool')) {
1297
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1298
        } else {
1299
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1300
        }
1301
1302
        $this->assign('profile_url', $profile_url);
1303
1304
        //Message link
1305
        $message_link = null;
1306
        $message_url = null;
1307
        if ('true' == api_get_setting('allow_message_tool')) {
1308
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1309
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1310
        }
1311
        $this->assign('message_link', $message_link);
1312
        $this->assign('message_url', $message_url);
1313
1314
        $pendingSurveyLink = '';
1315
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1316
        if ($show) {
1317
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1318
        }
1319
        $this->assign('pending_survey_url', $pendingSurveyLink);
1320
1321
        // Certificate Link
1322
        $allow = api_get_configuration_value('certificate.hide_my_certificate_link');
1323
        if (false === $allow) {
1324
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1325
            $certificateLink = Display::url(
1326
                get_lang('My certificates'),
1327
                $certificateUrl
1328
            );
1329
            $this->assign('certificate_link', $certificateLink);
1330
            $this->assign('certificate_url', $certificateUrl);
1331
        }
1332
1333
        $institution = api_get_setting('Institution');
1334
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1335
1336
        $this->assign('portal_name', $portal_name);
1337
1338
        //Menu
1339
        //$menu = menuArray();
1340
        //$this->assign('menu', $menu);
1341
1342
        $breadcrumb = '';
1343
        // Hide breadcrumb in LP
1344
        if (false == $this->show_learnpath) {
1345
            $breadcrumb = return_breadcrumb(
1346
                $interbreadcrumb,
1347
                $language_file,
1348
                $nameTools
1349
            );
1350
        }
1351
        $this->assign('breadcrumb', $breadcrumb);
1352
1353
        //Extra content
1354
        $extra_header = null;
1355
        if (!api_is_platform_admin()) {
1356
            $extra_header = trim(api_get_setting('header_extra_content'));
1357
        }
1358
        $this->assign('header_extra_content', $extra_header);
1359
1360
        if ($sendHeaders) {
1361
            /*header('Content-Type: text/html; charset='.api_get_system_encoding());
1362
            header(
1363
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1364
            );
1365
            self::addHTTPSecurityHeaders();*/
1366
1367
            $responseCode = $this->getResponseCode();
1368
            if (!empty($responseCode)) {
1369
                switch ($responseCode) {
1370
                    case '404':
1371
                        header("HTTP/1.0 404 Not Found");
1372
                        break;
1373
                }
1374
            }
1375
        }
1376
1377
        $socialMeta = '';
1378
        $metaTitle = api_get_setting('meta_title');
1379
        if (!empty($metaTitle)) {
1380
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1381
            $metaSite = api_get_setting('meta_twitter_site');
1382
            if (!empty($metaSite)) {
1383
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaSite of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1383
                $socialMeta .= '<meta name="twitter:site" content="'./** @scrutinizer ignore-type */ $metaSite.'" />'."\n";
Loading history...
1384
                $metaCreator = api_get_setting('meta_twitter_creator');
1385
                if (!empty($metaCreator)) {
1386
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaCreator of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1386
                    $socialMeta .= '<meta name="twitter:creator" content="'./** @scrutinizer ignore-type */ $metaCreator.'" />'."\n";
Loading history...
1387
                }
1388
            }
1389
1390
            // The user badge page emits its own meta tags, so if this is
1391
            // enabled, ignore the global ones
1392
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1393
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1394
1395
            if (!$userId && !$skillId) {
1396
                // no combination of user and skill ID has been defined,
1397
                // so print the normal OpenGraph meta tags
1398
                $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaTitle of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1398
                $socialMeta .= '<meta property="og:title" content="'./** @scrutinizer ignore-type */ $metaTitle.'" />'."\n";
Loading history...
1399
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1400
1401
                $metaDescription = api_get_setting('meta_description');
1402
                if (!empty($metaDescription)) {
1403
                    $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaDescription of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1403
                    $socialMeta .= '<meta property="og:description" content="'./** @scrutinizer ignore-type */ $metaDescription.'" />'."\n";
Loading history...
1404
                }
1405
1406
                $metaImage = api_get_setting('meta_image_path');
1407
                if (!empty($metaImage)) {
1408
                    if (is_file(api_get_path(SYS_PATH).$metaImage)) {
0 ignored issues
show
Bug introduced by
Are you sure $metaImage of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1408
                    if (is_file(api_get_path(SYS_PATH)./** @scrutinizer ignore-type */ $metaImage)) {
Loading history...
1409
                        $path = api_get_path(WEB_PATH).$metaImage;
1410
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1411
                    }
1412
                }
1413
            }
1414
        }
1415
1416
        $this->assign('social_meta', $socialMeta);
1417
    }
1418
1419
    /**
1420
     * Set footer parameters.
1421
     */
1422
    private function set_footer_parameters()
1423
    {
1424
        // Loading footer extra content
1425
        if (!api_is_platform_admin()) {
1426
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1427
            if (!empty($extra_footer)) {
1428
                $this->assign('footer_extra_content', $extra_footer);
1429
            }
1430
        }
1431
    }
1432
1433
    /**
1434
     * Manage specific HTTP headers security.
1435
     */
1436
    private function addHTTPSecurityHeaders()
1437
    {
1438
        // Implementation of HTTP headers security, as suggested and checked
1439
        // by https://securityheaders.io/
1440
        // Enable these settings in configuration.php to use them on your site
1441
        // Strict-Transport-Security
1442
        $setting = api_get_configuration_value('security_strict_transport');
1443
        if (!empty($setting)) {
1444
            header('Strict-Transport-Security: '.$setting);
1445
        }
1446
        // Content-Security-Policy
1447
        $setting = api_get_configuration_value('security_content_policy');
1448
        if (!empty($setting)) {
1449
            header('Content-Security-Policy: '.$setting);
1450
        }
1451
        $setting = api_get_configuration_value('security_content_policy_report_only');
1452
        if (!empty($setting)) {
1453
            header('Content-Security-Policy-Report-Only: '.$setting);
1454
        }
1455
        // Public-Key-Pins
1456
        $setting = api_get_configuration_value('security_public_key_pins');
1457
        if (!empty($setting)) {
1458
            header('Public-Key-Pins: '.$setting);
1459
        }
1460
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1461
        if (!empty($setting)) {
1462
            header('Public-Key-Pins-Report-Only: '.$setting);
1463
        }
1464
        // X-Frame-Options
1465
        $setting = api_get_configuration_value('security_x_frame_options');
1466
        if (!empty($setting)) {
1467
            header('X-Frame-Options: '.$setting);
1468
        }
1469
        // X-XSS-Protection
1470
        $setting = api_get_configuration_value('security_xss_protection');
1471
        if (!empty($setting)) {
1472
            header('X-XSS-Protection: '.$setting);
1473
        }
1474
        // X-Content-Type-Options
1475
        $setting = api_get_configuration_value('security_x_content_type_options');
1476
        if (!empty($setting)) {
1477
            header('X-Content-Type-Options: '.$setting);
1478
        }
1479
        // Referrer-Policy
1480
        $setting = api_get_configuration_value('security_referrer_policy');
1481
        if (!empty($setting)) {
1482
            header('Referrer-Policy: '.$setting);
1483
        }
1484
        // end of HTTP headers security block
1485
    }
1486
1487
    /**
1488
     * Assign favicon to the 'favico' template variable.
1489
     *
1490
     * @return bool Always return true because there is always at least one correct favicon.ico
1491
     */
1492
    private function assignFavIcon()
1493
    {
1494
        // Default root chamilo favicon
1495
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1496
1497
        //Added to verify if in the current Chamilo Theme exist a favicon
1498
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1499
1500
        //If exist pick the current chamilo theme favicon
1501
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1502
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1503
        }
1504
1505
        if (api_is_multiple_url_enabled()) {
1506
            /*$access_url_id = api_get_current_access_url_id();
1507
            if ($access_url_id != -1) {
1508
                $url_info = api_get_access_url($access_url_id);
1509
                $url = api_remove_trailing_slash(
1510
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1511
                );
1512
                $clean_url = api_replace_dangerous_char($url);
1513
                $clean_url = str_replace('/', '-', $clean_url);
1514
                $clean_url .= '/';
1515
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1516
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1517
                //we create the new dir for the new sites
1518
                if (is_file($icon_real_homep.'favicon.ico')) {
1519
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1520
                }
1521
            }*/
1522
        }
1523
1524
        $this->assign('favico', $favico);
1525
1526
        return true;
1527
    }
1528
1529
    /**
1530
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1531
     *
1532
     * @return bool Always return true (even if empty string)
1533
     */
1534
    private function assignAccessibilityBlock()
1535
    {
1536
        $resize = '';
1537
        if ('true' == api_get_setting('accessibility_font_resize')) {
1538
            $resize .= '<div class="resize_font">';
1539
            $resize .= '<div class="btn-group">';
1540
            $resize .= '<a title="'.get_lang('Decrease the font size').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1541
            $resize .= '<a title="'.get_lang('Reset the font size').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1542
            $resize .= '<a title="'.get_lang('Increase the font size').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1543
            $resize .= '</div>';
1544
            $resize .= '</div>';
1545
        }
1546
        $this->assign('accessibility', $resize);
1547
1548
        return true;
1549
    }
1550
1551
    /**
1552
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1553
     *
1554
     * @return bool Always return true (even if empty string)
1555
     */
1556
    private function assignSocialMeta()
1557
    {
1558
        $socialMeta = '';
1559
        $metaTitle = api_get_setting('meta_title');
1560
        if (!empty($metaTitle)) {
1561
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1562
            $metaSite = api_get_setting('meta_twitter_site');
1563
            if (!empty($metaSite)) {
1564
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaSite of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1564
                $socialMeta .= '<meta name="twitter:site" content="'./** @scrutinizer ignore-type */ $metaSite.'" />'."\n";
Loading history...
1565
                $metaCreator = api_get_setting('meta_twitter_creator');
1566
                if (!empty($metaCreator)) {
1567
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaCreator of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1567
                    $socialMeta .= '<meta name="twitter:creator" content="'./** @scrutinizer ignore-type */ $metaCreator.'" />'."\n";
Loading history...
1568
                }
1569
            }
1570
1571
            // The user badge page emits its own meta tags, so if this is
1572
            // enabled, ignore the global ones
1573
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1574
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1575
1576
            if (!$userId && !$skillId) {
1577
                // no combination of user and skill ID has been defined,
1578
                // so print the normal or course-specific OpenGraph meta tags
1579
                // Check for a course ID
1580
                $courseId = api_get_course_int_id();
1581
                // Check session ID from session/id/about (see .htaccess)
1582
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1583
1584
                if (false != $courseId) {
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...
1585
                    // If we are inside a course (even if within a session), publish info about the course
1586
                    $course = api_get_course_entity($courseId);
1587
                    // @TODO: support right-to-left in title
1588
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaTitle of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1588
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - './** @scrutinizer ignore-type */ $metaTitle.'" />'."\n";
Loading history...
1589
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1590
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
1591
1592
                    $metaDescription = api_get_setting('meta_description');
1593
                    if (!empty($course->getDescription())) {
1594
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1595
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1596
                    } elseif (!empty($metaDescription)) {
1597
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaDescription of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1597
                        $socialMeta .= '<meta property="og:description" content="'./** @scrutinizer ignore-type */ $metaDescription.'" />'."\n";
Loading history...
1598
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1599
                    }
1600
1601
                    $picture = Container::getIllustrationRepository()->getIllustrationUrl($course);
1602
                    if (!empty($picture)) {
1603
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1604
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
1605
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1606
                    } else {
1607
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1608
                    }
1609
                } elseif (0 !== $sessionId) {
1610
                    // If we are on a session "about" screen, publish info about the session
1611
                    $session = api_get_session_entity($sessionId);
1612
1613
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1614
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1615
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."sessions/{$session->getId()}/about/".'" />'."\n";
1616
1617
                    $sessionValues = new ExtraFieldValue('session');
1618
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1619
                    //$sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1620
                    if (!empty($sessionImage)) {
1621
                        $asset = Container::getAssetRepository()->find($sessionImage);
1622
                        $sessionImagePath = Container::getAssetRepository()->getAssetUrl($asset);
1623
                        if (!empty($sessionImagePath)) {
1624
                            $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1625
                            $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
1626
                            $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1627
                        }
1628
                    } else {
1629
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1630
                    }
1631
                } else {
1632
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
1633
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1634
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
1635
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1636
1637
                    $metaDescription = api_get_setting('meta_description');
1638
                    if (!empty($metaDescription)) {
1639
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1640
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1641
                    }
1642
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1643
                }
1644
            }
1645
        }
1646
1647
        $this->assign('social_meta', $socialMeta);
1648
1649
        return true;
1650
    }
1651
1652
    /**
1653
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
1654
     *
1655
     * @param string $imageAlt The alt attribute for the image
1656
     *
1657
     * @return string The meta image HTML tag, or empty
1658
     */
1659
    private function getMetaPortalImagePath($imageAlt = '')
1660
    {
1661
        // Load portal meta image if defined
1662
        $metaImage = api_get_setting('meta_image_path');
1663
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
0 ignored issues
show
Bug introduced by
Are you sure $metaImage of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1663
        $metaImageSysPath = api_get_path(SYS_PATH)./** @scrutinizer ignore-type */ $metaImage;
Loading history...
1664
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
1665
        $portalImageMeta = '';
1666
        if (!empty($metaImage)) {
1667
            if (is_file($metaImageSysPath)) {
1668
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
1669
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
1670
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1671
            }
1672
        } else {
1673
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
1674
            if (!empty($logo)) {
1675
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
1676
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
1677
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1678
            }
1679
        }
1680
1681
        return $portalImageMeta;
1682
    }
1683
}
1684