Passed
Push — master ( 15bb7c...3ad356 )
by Julito
10:34
created

Template::getGlobals()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 11
rs 10
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\Filesystem\Exception\FileNotFoundException;
10
use Symfony\Component\HttpFoundation\Response;
11
12
/**
13
 * Class Template.
14
 *
15
 * @author Julio Montoya <[email protected]>
16
 *
17
 * @todo better organization of the class, methods and variables
18
 */
19
class Template
20
{
21
    /**
22
     * The Template folder name see main/template.
23
     *
24
     * @var string
25
     */
26
    public $templateFolder = 'default';
27
28
    /**
29
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
30
     * This variable is set from the database.
31
     *
32
     * @var string
33
     */
34
    public $theme = '';
35
36
    /**
37
     * @var string
38
     */
39
    public $preview_theme = '';
40
    public $title = null;
41
    public $show_header;
42
    public $show_footer;
43
    public $help;
44
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
45
    public $show_learnpath = false; // This is a learnpath section or not?
46
    public $plugin = null;
47
    public $course_id = null;
48
    public $user_is_logged_in = false;
49
    public $twig = null;
50
51
    /* Loads chamilo plugins */
52
    public $load_plugins = false;
53
    public $params = [];
54
    public $force_plugin_load = false;
55
    public $responseCode = 0;
56
    private $themeDir;
57
58
    /**
59
     * @param string $title
60
     * @param bool   $show_header
61
     * @param bool   $show_footer
62
     * @param bool   $show_learnpath
63
     * @param bool   $hide_global_chat
64
     * @param bool   $load_plugins
65
     * @param int    $responseCode
66
     * @param bool   $sendHeaders      send http headers or not
67
     */
68
    public function __construct(
69
        $title = '',
70
        $show_header = true,
71
        $show_footer = true,
72
        $show_learnpath = false,
73
        $hide_global_chat = false,
74
        $load_plugins = true,
75
        $sendHeaders = true,
76
        $responseCode = 0
77
    ) {
78
        // Page title
79
        $this->title = $title;
80
        global $interbreadcrumb;
81
        $interbreadcrumb[] = ['url' => '#', 'name' => $title];
82
        $this->show_learnpath = $show_learnpath;
83
        //$this->setResponseCode($responseCode);
84
85
        if (empty($this->show_learnpath)) {
86
            $origin = api_get_origin();
87
            if ('learnpath' === $origin) {
88
                $this->show_learnpath = true;
89
                $show_footer = false;
90
                $show_header = false;
91
            }
92
        }
93
        $this->hide_global_chat = $hide_global_chat;
94
        $this->load_plugins = $load_plugins;
95
96
        /*$template_paths = [
97
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
98
            api_get_path(SYS_CODE_PATH).'template', //template folder
99
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
100
            api_get_path(SYS_PATH).'src/ThemeBundle/Resources/views',
101
        ];*/
102
103
        $this->twig = Container::getTwig();
104
105
        // Setting system variables
106
        //$this->set_system_parameters();
107
108
        // Setting user variables
109
        //$this->set_user_parameters();
110
111
        // Setting course variables
112
        //$this->set_course_parameters();
113
114
        // Setting administrator variables
115
        //$this->setAdministratorParams();
116
        //$this->setCSSEditor();
117
118
        // Header and footer are showed by default
119
        //$this->set_footer($show_footer);
120
        //$this->set_header($show_header);
121
122
        //$this->set_header_parameters($sendHeaders);
123
        //$this->set_footer_parameters();
124
125
        $defaultStyle = api_get_setting('display.default_template');
126
        if (!empty($defaultStyle)) {
127
            $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...
128
        }
129
    }
130
131
    /**
132
     * @param string $helpInput
133
     */
134
    public function setHelp($helpInput = null)
135
    {
136
        if (!empty($helpInput)) {
137
            $help = $helpInput;
138
        } else {
139
            $help = $this->help;
140
        }
141
142
        $content = '';
143
        if ('true' == api_get_setting('enable_help_link')) {
144
            if (!empty($help)) {
145
                $help = Security::remove_XSS($help);
146
                $content = '<div class="help">';
147
                $content .= Display::url(
148
                    Display::return_icon('help.png', get_lang('Help'), null, ICON_SIZE_LARGE),
149
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
0 ignored issues
show
Bug introduced by
Are you sure $help 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

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

856
        $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...
857
        $form->addHidden('_csrf_token', $token->getValue());
858
859
        // Captcha
860
        $captcha = api_get_setting('allow_captcha');
861
        $allowCaptcha = 'true' === $captcha;
862
863
        if ($allowCaptcha) {
864
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
865
            if ($useCaptcha) {
866
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
867
                $options = [
868
                    'width' => 250,
869
                    'height' => 90,
870
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
871
                    'sessionVar' => basename(__FILE__, '.php'),
872
                    'imageOptions' => [
873
                        'font_size' => 20,
874
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
875
                        'font_file' => 'OpenSans-Regular.ttf',
876
                        //'output' => 'gif'
877
                    ],
878
                ];
879
880
                // Minimum options using all defaults (including defaults for Image_Text):
881
                //$options = array('callback' => 'qfcaptcha_image.php');
882
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
883
                $form->addHtml(get_lang('Click on the image to load a new one.'));
884
885
                $form->addElement(
886
                    'text',
887
                    'captcha',
888
                    get_lang('Enter the letters you see.')
889
                );
890
                $form->addRule(
891
                    'captcha',
892
                    get_lang('Enter the characters you see on the image'),
893
                    'required',
894
                    null,
895
                    'client'
896
                );
897
                $form->addRule(
898
                    'captcha',
899
                    get_lang('The text you entered doesn\'t match the picture.'),
900
                    'CAPTCHA',
901
                    $captcha_question
902
                );
903
            }
904
        }
905
906
        $form->addButton(
907
            'submitAuth',
908
            get_lang('Login'),
909
            null,
910
            'primary',
911
            null,
912
            'btn-block'
913
        );
914
915
        $html = $form->returnForm();
916
917
        return $html;
918
    }
919
920
    /**
921
     * Returns the tutors names for the current course in session
922
     * Function to use in Twig templates.
923
     *
924
     * @return string
925
     */
926
    public static function returnTutorsNames()
927
    {
928
        $em = Database::getManager();
929
        $tutors = $em
930
            ->createQuery('
931
                SELECT u FROM ChamiloCoreBundle:User u
932
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
933
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
934
            ')
935
            ->setParameters([
936
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
937
                'session' => api_get_session_id(),
938
                'course' => api_get_course_int_id(),
939
            ])
940
            ->getResult();
941
942
        $names = [];
943
944
        /** @var User $tutor */
945
        foreach ($tutors as $tutor) {
946
            $names[] = UserManager::formatUserFullName($tutor);
947
        }
948
949
        return implode(CourseManager::USER_SEPARATOR, $names);
950
    }
951
952
    /**
953
     * @param int $code
954
     */
955
    public function setResponseCode($code)
956
    {
957
        $this->responseCode = $code;
958
    }
959
960
    public function getResponseCode()
961
    {
962
        return $this->responseCode;
963
    }
964
965
    /**
966
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
967
     *
968
     * @return bool Always return true because there is always a string, even if empty
969
     */
970
    public function assignBugNotification()
971
    {
972
        //@todo move this in the template
973
        $rightFloatMenu = '';
974
        $iconBug = Display::return_icon(
975
            'bug.png',
976
            get_lang('Report a bug'),
977
            [],
978
            ICON_SIZE_LARGE
979
        );
980
        if ('true' === api_get_setting('show_link_bug_notification') && $this->user_is_logged_in) {
981
            $rightFloatMenu = '<div class="report">
982
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
983
                    '.$iconBug.'
984
                </a>
985
		        </div>';
986
        }
987
988
        if ('true' === api_get_setting('show_link_ticket_notification') &&
989
            $this->user_is_logged_in
990
        ) {
991
            // by default is project_id = 1
992
            $defaultProjectId = 1;
993
            $iconTicket = Display::return_icon(
994
                'help.png',
995
                get_lang('Ticket'),
996
                [],
997
                ICON_SIZE_LARGE
998
            );
999
            $courseInfo = api_get_course_info();
1000
            $courseParams = '';
1001
            if (!empty($courseInfo)) {
1002
                $courseParams = api_get_cidreq();
1003
            }
1004
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams;
1005
1006
            $allow = TicketManager::userIsAllowInProject(api_get_user_info(), $defaultProjectId);
1007
1008
            if ($allow) {
1009
                $rightFloatMenu .= '<div class="help">
1010
                    <a href="'.$url.'" target="_blank">
1011
                        '.$iconTicket.'
1012
                    </a>
1013
                </div>';
1014
            }
1015
        }
1016
1017
        $this->assign('bug_notification', $rightFloatMenu);
1018
1019
        return true;
1020
    }
1021
1022
    /**
1023
     * Load legacy params.
1024
     */
1025
    private function loadLegacyParams()
1026
    {
1027
        // Set legacy breadcrumb
1028
        global $interbreadcrumb;
1029
1030
        $courseInfo = api_get_course_info();
1031
        if (!empty($courseInfo)) {
1032
            $url = $courseInfo['course_public_url'];
1033
            $sessionId = api_get_session_id();
1034
            if (!empty($sessionId)) {
1035
                $url .= '?sid='.$sessionId;
1036
            }
1037
            array_unshift(
1038
                $interbreadcrumb,
1039
                ['name' => $courseInfo['title'], 'url' => $url]
1040
            );
1041
        }
1042
1043
        $this->params['legacy_breadcrumb'] = json_encode($interbreadcrumb);
1044
1045
        global $htmlHeadXtra;
1046
        $this->params['legacy_javascript'] = $htmlHeadXtra;
1047
    }
1048
1049
    /**
1050
     * Prepare the _c array for template files. The _c array contains
1051
     * information about the current course.
1052
     */
1053
    private function set_course_parameters()
1054
    {
1055
        //Setting course id
1056
        $course = api_get_course_info();
1057
        if (empty($course)) {
1058
            $this->assign('course_is_set', false);
1059
1060
            return;
1061
        }
1062
        $this->assign('course_is_set', true);
1063
        $this->course_id = $course['id'];
1064
        $_c = [
1065
            'id' => $course['real_id'],
1066
            'code' => $course['code'],
1067
            'title' => $course['name'],
1068
            'visibility' => $course['visibility'],
1069
            'language' => $course['language'],
1070
            'directory' => $course['directory'],
1071
            'session_id' => api_get_session_id(),
1072
            'user_is_teacher' => api_is_course_admin(),
1073
            'student_view' => (!empty($_GET['isStudentView']) && 'true' == $_GET['isStudentView']),
1074
        ];
1075
        $this->assign('course_code', $course['code']);
1076
        $this->assign('_c', $_c);
1077
    }
1078
1079
    /**
1080
     * Set header parameters.
1081
     *
1082
     * @deprecated
1083
     *
1084
     * @param bool $sendHeaders send headers
1085
     */
1086
    private function set_header_parameters($sendHeaders)
1087
    {
1088
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1089
        $_course = api_get_course_info();
1090
        $nameTools = $this->title;
1091
        $navigation = return_navigation_array();
1092
        $this->menu_navigation = $navigation['menu_navigation'];
1093
1094
        $this->assign('system_charset', api_get_system_encoding());
1095
1096
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1097
            foreach ($httpHeadXtra as &$thisHttpHead) {
1098
                //header($thisHttpHead);
1099
            }
1100
        }
1101
1102
        $this->assign(
1103
            'online_button',
1104
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
1105
        );
1106
        $this->assign(
1107
            'offline_button',
1108
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
1109
        );
1110
1111
        // Get language iso-code for this page - ignore errors
1112
        $this->assign('document_language', api_get_language_isocode());
1113
1114
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1115
1116
        $title_list = [];
1117
1118
        $title_list[] = api_get_setting('Institution');
1119
        $title_list[] = api_get_setting('siteName');
1120
1121
        if (!empty($course_title)) {
1122
            $title_list[] = $course_title;
1123
        }
1124
        if ('' != $nameTools) {
1125
            $title_list[] = $nameTools;
1126
        }
1127
1128
        $title_string = '';
1129
        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...
1130
            $title_string .= $title_list[$i];
1131
            if (isset($title_list[$i + 1])) {
1132
                $item = trim($title_list[$i + 1]);
1133
                if (!empty($item)) {
1134
                    $title_string .= ' - ';
1135
                }
1136
            }
1137
        }
1138
1139
        $this->assign('title_string', $title_string);
1140
1141
        // Setting the theme and CSS files
1142
        //$this->setCssFiles();
1143
        $this->set_js_files();
1144
        $this->setCssCustomFiles();
1145
1146
        /*$browser = api_browser_support('check_browser');
1147
        if ('Internet Explorer' == $browser[0] && $browser[1] >= '11') {
1148
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1149
            $this->assign('browser_specific_head', $browser_head);
1150
        }*/
1151
1152
        // Implementation of prefetch.
1153
        // See http://cdn.chamilo.org/main/img/online.png for details
1154
        $prefetch = '';
1155
        if (!empty($_configuration['cdn_enable'])) {
1156
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1157
            foreach ($_configuration['cdn'] as $host => $exts) {
1158
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1159
            }
1160
        }
1161
1162
        $this->assign('prefetch', $prefetch);
1163
        $this->assign('text_direction', api_get_text_direction());
1164
        $this->assign('section_name', 'section-'.$this_section);
1165
        $this->assignFavIcon();
1166
        $this->setHelp();
1167
1168
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1169
1170
        $this->assignAccessibilityBlock(); //Prepare the 'accessibility' var for the template
1171
1172
        // Preparing values for the menu
1173
1174
        // Logout link
1175
        $hideLogout = api_get_setting('hide_logout_button');
1176
        if ('true' === $hideLogout) {
1177
            $this->assign('logout_link', null);
1178
        } else {
1179
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1180
        }
1181
1182
        // Profile link
1183
        if ('true' == api_get_setting('allow_social_tool')) {
1184
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1185
        } else {
1186
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1187
        }
1188
1189
        $this->assign('profile_url', $profile_url);
1190
1191
        //Message link
1192
        $message_link = null;
1193
        $message_url = null;
1194
        if ('true' == api_get_setting('allow_message_tool')) {
1195
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1196
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1197
        }
1198
        $this->assign('message_link', $message_link);
1199
        $this->assign('message_url', $message_url);
1200
1201
        $pendingSurveyLink = '';
1202
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1203
        if ($show) {
1204
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1205
        }
1206
        $this->assign('pending_survey_url', $pendingSurveyLink);
1207
1208
        // Certificate Link
1209
        $allow = api_get_configuration_value('certificate.hide_my_certificate_link');
1210
        if (false === $allow) {
1211
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1212
            $certificateLink = Display::url(
1213
                get_lang('My certificates'),
1214
                $certificateUrl
1215
            );
1216
            $this->assign('certificate_link', $certificateLink);
1217
            $this->assign('certificate_url', $certificateUrl);
1218
        }
1219
1220
        $institution = api_get_setting('Institution');
1221
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1222
1223
        $this->assign('portal_name', $portal_name);
1224
1225
        //Menu
1226
        //$menu = menuArray();
1227
        //$this->assign('menu', $menu);
1228
1229
        $breadcrumb = '';
1230
        // Hide breadcrumb in LP
1231
        if (false == $this->show_learnpath) {
1232
            $breadcrumb = return_breadcrumb(
1233
                $interbreadcrumb,
1234
                $language_file,
1235
                $nameTools
1236
            );
1237
        }
1238
        $this->assign('breadcrumb', $breadcrumb);
1239
1240
        //Extra content
1241
        $extra_header = null;
1242
        if (!api_is_platform_admin()) {
1243
            $extra_header = trim(api_get_setting('header_extra_content'));
1244
        }
1245
        $this->assign('header_extra_content', $extra_header);
1246
1247
        if ($sendHeaders) {
1248
            /*header('Content-Type: text/html; charset='.api_get_system_encoding());
1249
            header(
1250
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1251
            );
1252
            self::addHTTPSecurityHeaders();*/
1253
1254
            $responseCode = $this->getResponseCode();
1255
            if (!empty($responseCode)) {
1256
                switch ($responseCode) {
1257
                    case '404':
1258
                        header("HTTP/1.0 404 Not Found");
1259
                        break;
1260
                }
1261
            }
1262
        }
1263
1264
        $socialMeta = '';
1265
        $metaTitle = api_get_setting('meta_title');
1266
        if (!empty($metaTitle)) {
1267
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1268
            $metaSite = api_get_setting('meta_twitter_site');
1269
            if (!empty($metaSite)) {
1270
                $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

1270
                $socialMeta .= '<meta name="twitter:site" content="'./** @scrutinizer ignore-type */ $metaSite.'" />'."\n";
Loading history...
1271
                $metaCreator = api_get_setting('meta_twitter_creator');
1272
                if (!empty($metaCreator)) {
1273
                    $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

1273
                    $socialMeta .= '<meta name="twitter:creator" content="'./** @scrutinizer ignore-type */ $metaCreator.'" />'."\n";
Loading history...
1274
                }
1275
            }
1276
1277
            // The user badge page emits its own meta tags, so if this is
1278
            // enabled, ignore the global ones
1279
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1280
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1281
1282
            if (!$userId && !$skillId) {
1283
                // no combination of user and skill ID has been defined,
1284
                // so print the normal OpenGraph meta tags
1285
                $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

1285
                $socialMeta .= '<meta property="og:title" content="'./** @scrutinizer ignore-type */ $metaTitle.'" />'."\n";
Loading history...
1286
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1287
1288
                $metaDescription = api_get_setting('meta_description');
1289
                if (!empty($metaDescription)) {
1290
                    $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

1290
                    $socialMeta .= '<meta property="og:description" content="'./** @scrutinizer ignore-type */ $metaDescription.'" />'."\n";
Loading history...
1291
                }
1292
1293
                $metaImage = api_get_setting('meta_image_path');
1294
                if (!empty($metaImage)) {
1295
                    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

1295
                    if (is_file(api_get_path(SYS_PATH)./** @scrutinizer ignore-type */ $metaImage)) {
Loading history...
1296
                        $path = api_get_path(WEB_PATH).$metaImage;
1297
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1298
                    }
1299
                }
1300
            }
1301
        }
1302
1303
        $this->assign('social_meta', $socialMeta);
1304
    }
1305
1306
    /**
1307
     * Set footer parameters.
1308
     */
1309
    private function set_footer_parameters()
1310
    {
1311
        // Loading footer extra content
1312
        if (!api_is_platform_admin()) {
1313
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1314
            if (!empty($extra_footer)) {
1315
                $this->assign('footer_extra_content', $extra_footer);
1316
            }
1317
        }
1318
    }
1319
1320
    /**
1321
     * Manage specific HTTP headers security.
1322
     */
1323
    private function addHTTPSecurityHeaders()
1324
    {
1325
        // Implementation of HTTP headers security, as suggested and checked
1326
        // by https://securityheaders.io/
1327
        // Enable these settings in configuration.php to use them on your site
1328
        // Strict-Transport-Security
1329
        $setting = api_get_configuration_value('security_strict_transport');
1330
        if (!empty($setting)) {
1331
            header('Strict-Transport-Security: '.$setting);
1332
        }
1333
        // Content-Security-Policy
1334
        $setting = api_get_configuration_value('security_content_policy');
1335
        if (!empty($setting)) {
1336
            header('Content-Security-Policy: '.$setting);
1337
        }
1338
        $setting = api_get_configuration_value('security_content_policy_report_only');
1339
        if (!empty($setting)) {
1340
            header('Content-Security-Policy-Report-Only: '.$setting);
1341
        }
1342
        // Public-Key-Pins
1343
        $setting = api_get_configuration_value('security_public_key_pins');
1344
        if (!empty($setting)) {
1345
            header('Public-Key-Pins: '.$setting);
1346
        }
1347
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1348
        if (!empty($setting)) {
1349
            header('Public-Key-Pins-Report-Only: '.$setting);
1350
        }
1351
        // X-Frame-Options
1352
        $setting = api_get_configuration_value('security_x_frame_options');
1353
        if (!empty($setting)) {
1354
            header('X-Frame-Options: '.$setting);
1355
        }
1356
        // X-XSS-Protection
1357
        $setting = api_get_configuration_value('security_xss_protection');
1358
        if (!empty($setting)) {
1359
            header('X-XSS-Protection: '.$setting);
1360
        }
1361
        // X-Content-Type-Options
1362
        $setting = api_get_configuration_value('security_x_content_type_options');
1363
        if (!empty($setting)) {
1364
            header('X-Content-Type-Options: '.$setting);
1365
        }
1366
        // Referrer-Policy
1367
        $setting = api_get_configuration_value('security_referrer_policy');
1368
        if (!empty($setting)) {
1369
            header('Referrer-Policy: '.$setting);
1370
        }
1371
        // end of HTTP headers security block
1372
    }
1373
1374
    /**
1375
     * Assign favicon to the 'favico' template variable.
1376
     *
1377
     * @return bool Always return true because there is always at least one correct favicon.ico
1378
     */
1379
    private function assignFavIcon()
1380
    {
1381
        // Default root chamilo favicon
1382
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1383
1384
        //Added to verify if in the current Chamilo Theme exist a favicon
1385
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1386
1387
        //If exist pick the current chamilo theme favicon
1388
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1389
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1390
        }
1391
1392
        if (api_is_multiple_url_enabled()) {
1393
            /*$access_url_id = api_get_current_access_url_id();
1394
            if ($access_url_id != -1) {
1395
                $url_info = api_get_access_url($access_url_id);
1396
                $url = api_remove_trailing_slash(
1397
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1398
                );
1399
                $clean_url = api_replace_dangerous_char($url);
1400
                $clean_url = str_replace('/', '-', $clean_url);
1401
                $clean_url .= '/';
1402
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1403
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1404
                //we create the new dir for the new sites
1405
                if (is_file($icon_real_homep.'favicon.ico')) {
1406
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1407
                }
1408
            }*/
1409
        }
1410
1411
        $this->assign('favico', $favico);
1412
1413
        return true;
1414
    }
1415
1416
    /**
1417
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1418
     *
1419
     * @return bool Always return true (even if empty string)
1420
     */
1421
    private function assignAccessibilityBlock()
1422
    {
1423
        $resize = '';
1424
        if ('true' == api_get_setting('accessibility_font_resize')) {
1425
            $resize .= '<div class="resize_font">';
1426
            $resize .= '<div class="btn-group">';
1427
            $resize .= '<a title="'.get_lang('Decrease the font size').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1428
            $resize .= '<a title="'.get_lang('Reset the font size').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1429
            $resize .= '<a title="'.get_lang('Increase the font size').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1430
            $resize .= '</div>';
1431
            $resize .= '</div>';
1432
        }
1433
        $this->assign('accessibility', $resize);
1434
1435
        return true;
1436
    }
1437
1438
    /**
1439
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1440
     *
1441
     * @return bool Always return true (even if empty string)
1442
     */
1443
    private function assignSocialMeta()
1444
    {
1445
        $socialMeta = '';
1446
        $metaTitle = api_get_setting('meta_title');
1447
        if (!empty($metaTitle)) {
1448
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1449
            $metaSite = api_get_setting('meta_twitter_site');
1450
            if (!empty($metaSite)) {
1451
                $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

1451
                $socialMeta .= '<meta name="twitter:site" content="'./** @scrutinizer ignore-type */ $metaSite.'" />'."\n";
Loading history...
1452
                $metaCreator = api_get_setting('meta_twitter_creator');
1453
                if (!empty($metaCreator)) {
1454
                    $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

1454
                    $socialMeta .= '<meta name="twitter:creator" content="'./** @scrutinizer ignore-type */ $metaCreator.'" />'."\n";
Loading history...
1455
                }
1456
            }
1457
1458
            // The user badge page emits its own meta tags, so if this is
1459
            // enabled, ignore the global ones
1460
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1461
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1462
1463
            if (!$userId && !$skillId) {
1464
                // no combination of user and skill ID has been defined,
1465
                // so print the normal or course-specific OpenGraph meta tags
1466
                // Check for a course ID
1467
                $courseId = api_get_course_int_id();
1468
                // Check session ID from session/id/about (see .htaccess)
1469
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1470
1471
                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...
1472
                    // If we are inside a course (even if within a session), publish info about the course
1473
                    $course = api_get_course_entity($courseId);
1474
                    // @TODO: support right-to-left in title
1475
                    $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

1475
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - './** @scrutinizer ignore-type */ $metaTitle.'" />'."\n";
Loading history...
1476
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1477
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
1478
1479
                    $metaDescription = api_get_setting('meta_description');
1480
                    if (!empty($course->getDescription())) {
1481
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1482
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1483
                    } elseif (!empty($metaDescription)) {
1484
                        $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

1484
                        $socialMeta .= '<meta property="og:description" content="'./** @scrutinizer ignore-type */ $metaDescription.'" />'."\n";
Loading history...
1485
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1486
                    }
1487
1488
                    $picture = Container::getIllustrationRepository()->getIllustrationUrl($course);
1489
                    if (!empty($picture)) {
1490
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1491
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
1492
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1493
                    } else {
1494
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1495
                    }
1496
                } elseif (0 !== $sessionId) {
1497
                    // If we are on a session "about" screen, publish info about the session
1498
                    $session = api_get_session_entity($sessionId);
1499
1500
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1501
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1502
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."sessions/{$session->getId()}/about/".'" />'."\n";
1503
1504
                    $sessionValues = new ExtraFieldValue('session');
1505
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1506
                    //$sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1507
                    if (!empty($sessionImage)) {
1508
                        $asset = Container::getAssetRepository()->find($sessionImage);
1509
                        $sessionImagePath = Container::getAssetRepository()->getAssetUrl($asset);
1510
                        if (!empty($sessionImagePath)) {
1511
                            $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1512
                            $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
1513
                            $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1514
                        }
1515
                    } else {
1516
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1517
                    }
1518
                } else {
1519
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
1520
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1521
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
1522
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1523
1524
                    $metaDescription = api_get_setting('meta_description');
1525
                    if (!empty($metaDescription)) {
1526
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1527
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1528
                    }
1529
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1530
                }
1531
            }
1532
        }
1533
1534
        $this->assign('social_meta', $socialMeta);
1535
1536
        return true;
1537
    }
1538
1539
    /**
1540
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
1541
     *
1542
     * @param string $imageAlt The alt attribute for the image
1543
     *
1544
     * @return string The meta image HTML tag, or empty
1545
     */
1546
    private function getMetaPortalImagePath($imageAlt = '')
1547
    {
1548
        // Load portal meta image if defined
1549
        $metaImage = api_get_setting('meta_image_path');
1550
        $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

1550
        $metaImageSysPath = api_get_path(SYS_PATH)./** @scrutinizer ignore-type */ $metaImage;
Loading history...
1551
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
1552
        $portalImageMeta = '';
1553
        if (!empty($metaImage)) {
1554
            if (is_file($metaImageSysPath)) {
1555
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
1556
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
1557
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1558
            }
1559
        } else {
1560
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
1561
            if (!empty($logo)) {
1562
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
1563
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
1564
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1565
            }
1566
        }
1567
1568
        return $portalImageMeta;
1569
    }
1570
}
1571