Passed
Push — 1.11.x ( f2df5d...ca2e7a )
by Angel Fernando Quiroz
12:02
created

Template::setAdministratorParams()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 10
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\UserBundle\Entity\User;
8
9
/**
10
 * Class Template.
11
 *
12
 * @author Julio Montoya <[email protected]>
13
 *
14
 * @todo better organization of the class, methods and variables
15
 */
16
class Template
17
{
18
    /**
19
     * The Template folder name see main/template.
20
     *
21
     * @var string
22
     */
23
    public $templateFolder = 'default';
24
25
    /**
26
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
27
     * This variable is set from the database.
28
     *
29
     * @var string
30
     */
31
    public $theme = '';
32
33
    /**
34
     * @var string
35
     */
36
    public $preview_theme = '';
37
    public $title = null;
38
    public $show_header;
39
    public $show_footer;
40
    public $help;
41
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
42
    public $show_learnpath = false; // This is a learnpath section or not?
43
    public $plugin = null;
44
    public $course_id = null;
45
    public $user_is_logged_in = false;
46
    public $twig = null;
47
48
    /* Loads chamilo plugins */
49
    public $load_plugins = false;
50
    public $params = [];
51
    public $force_plugin_load = false;
52
    public $responseCode = 0;
53
    private $themeDir;
54
55
    /**
56
     * @param string $title
57
     * @param bool   $show_header
58
     * @param bool   $show_footer
59
     * @param bool   $show_learnpath
60
     * @param bool   $hide_global_chat
61
     * @param bool   $load_plugins
62
     * @param int    $responseCode
63
     * @param bool   $sendHeaders      send http headers or not
64
     */
65
    public function __construct(
66
        $title = '',
67
        $show_header = true,
68
        $show_footer = true,
69
        $show_learnpath = false,
70
        $hide_global_chat = false,
71
        $load_plugins = true,
72
        $sendHeaders = true,
73
        $responseCode = 0
74
    ) {
75
        // Page title
76
        $this->title = $title;
77
        $this->show_learnpath = $show_learnpath;
78
        $this->setResponseCode($responseCode);
79
80
        if (empty($this->show_learnpath)) {
81
            $origin = api_get_origin();
82
            if ($origin === 'learnpath') {
83
                $this->show_learnpath = true;
84
                $show_footer = false;
85
                $show_header = false;
86
            }
87
        }
88
        $this->hide_global_chat = $hide_global_chat;
89
        $this->load_plugins = $load_plugins;
90
91
        $template_paths = [
92
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
93
            api_get_path(SYS_CODE_PATH).'template', //template folder
94
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
95
        ];
96
97
        $urlId = api_get_current_access_url_id();
98
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
99
100
        if (!is_dir($cache_folder)) {
101
            mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
102
        }
103
104
        $loader = new Twig_Loader_Filesystem($template_paths);
105
106
        $isTestMode = api_get_setting('server_type') === 'test';
107
108
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
109
        if ($isTestMode) {
110
            $options = [
111
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
112
                'autoescape' => false,
113
                'debug' => true,
114
                'auto_reload' => true,
115
                'optimizations' => 0,
116
                // turn on optimizations with -1
117
                'strict_variables' => false,
118
                //If set to false, Twig will silently ignore invalid variables
119
            ];
120
        } else {
121
            $options = [
122
                'cache' => $cache_folder,
123
                //path to the cache folder
124
                'autoescape' => false,
125
                'debug' => false,
126
                'auto_reload' => false,
127
                'optimizations' => -1,
128
                // turn on optimizations with -1
129
                'strict_variables' => false,
130
                //If set to false, Twig will silently ignore invalid variables
131
            ];
132
        }
133
134
        $this->twig = new Twig_Environment($loader, $options);
135
136
        if ($isTestMode) {
137
            $this->twig->addExtension(new Twig_Extension_Debug());
138
        }
139
140
        // Twig filters setup
141
        $filters = [
142
            'var_dump',
143
            'get_plugin_lang',
144
            'get_lang',
145
            'api_get_path',
146
            'api_get_local_time',
147
            'api_convert_and_format_date',
148
            'api_is_allowed_to_edit',
149
            'api_get_user_info',
150
            'api_get_configuration_value',
151
            'api_get_setting',
152
            'api_get_course_setting',
153
            'api_get_plugin_setting',
154
            [
155
                'name' => 'return_message',
156
                'callable' => 'Display::return_message_and_translate',
157
            ],
158
            [
159
                'name' => 'display_page_header',
160
                'callable' => 'Display::page_header_and_translate',
161
            ],
162
            [
163
                'name' => 'display_page_subheader',
164
                'callable' => 'Display::page_subheader_and_translate',
165
            ],
166
            [
167
                'name' => 'icon',
168
                'callable' => 'Display::get_icon_path',
169
            ],
170
            [
171
                'name' => 'img',
172
                'callable' => 'Display::get_image',
173
            ],
174
            [
175
                'name' => 'format_date',
176
                'callable' => 'api_format_date',
177
            ],
178
            [
179
                'name' => 'get_template',
180
                'callable' => 'api_find_template',
181
            ],
182
            [
183
                'name' => 'date_to_time_ago',
184
                'callable' => 'Display::dateToStringAgoAndLongDate',
185
            ],
186
            [
187
                'name' => 'remove_xss',
188
                'callable' => 'Security::remove_XSS',
189
            ],
190
        ];
191
192
        foreach ($filters as $filter) {
193
            if (is_array($filter)) {
194
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
195
            } else {
196
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
197
            }
198
        }
199
200
        $functions = [
201
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
202
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
203
            ['name' => 'api_is_platform_admin', 'callable' => 'api_is_platform_admin'],
204
        ];
205
206
        foreach ($functions as $function) {
207
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
208
        }
209
210
        // Setting system variables
211
        $this->set_system_parameters();
212
213
        // Setting user variables
214
        $this->set_user_parameters();
215
216
        // Setting course variables
217
        $this->set_course_parameters();
218
219
        // Setting administrator variables
220
        $this->setAdministratorParams();
221
        //$this->setCSSEditor();
222
223
        // Header and footer are showed by default
224
        $this->set_footer($show_footer);
225
        $this->set_header($show_header);
226
227
        // Extra class for the main cm-content div
228
        global $htmlContentExtraClass;
229
        $this->setExtraContentClass($htmlContentExtraClass);
230
231
        $this->set_header_parameters($sendHeaders);
232
        $this->set_footer_parameters();
233
234
        $defaultStyle = api_get_configuration_value('default_template');
235
        if (!empty($defaultStyle)) {
236
            $this->templateFolder = $defaultStyle;
0 ignored issues
show
Documentation Bug introduced by
It seems like $defaultStyle can also be of type boolean. However, the property $templateFolder is declared as type string. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
237
        }
238
239
        $this->assign('template', $this->templateFolder);
240
        $this->assign('locale', api_get_language_isocode());
241
        $this->assign('login_class', null);
242
243
        $allow = api_get_configuration_value('show_language_selector_in_menu');
244
        if ($allow) {
245
            $this->assign('language_form', api_display_language_form());
246
        }
247
248
        if (api_get_configuration_value('notification_event')) {
249
            $this->assign('notification_event', '1');
250
        }
251
252
        // Chamilo plugins
253
        if ($this->show_header) {
254
            if ($this->load_plugins) {
255
                $this->plugin = new AppPlugin();
256
257
                //1. Showing installed plugins in regions
258
                $pluginRegions = $this->plugin->get_plugin_regions();
259
                foreach ($pluginRegions as $region) {
260
                    $this->set_plugin_region($region);
261
                }
262
263
                //2. Loading the course plugin info
264
                global $course_plugin;
265
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
266
                    //Load plugin get_langs
267
                    $this->plugin->load_plugin_lang_variables($course_plugin);
268
                }
269
            }
270
        }
271
    }
272
273
    /**
274
     * Return the item's url key:.
275
     *
276
     *      c_id=xx&id=xx
277
     *
278
     * @param object $item
279
     *
280
     * @return string
281
     */
282
    public static function key($item)
283
    {
284
        $id = isset($item->id) ? $item->id : null;
285
        $c_id = isset($item->c_id) ? $item->c_id : null;
286
        $result = '';
287
        if ($c_id) {
288
            $result = "c_id=$c_id";
289
        }
290
        if ($id) {
291
            if ($result) {
292
                $result .= "&amp;id=$id";
293
            } else {
294
                $result .= "&amp;id=$id";
295
            }
296
        }
297
298
        return $result;
299
    }
300
301
    /**
302
     * @param string $helpInput
303
     */
304
    public function setHelp($helpInput = null)
305
    {
306
        if (!empty($helpInput)) {
307
            $help = $helpInput;
308
        } else {
309
            $help = $this->help;
310
        }
311
312
        $content = '';
313
        if (api_get_setting('enable_help_link') == 'true') {
314
            if (!empty($help)) {
315
                $help = Security::remove_XSS($help);
316
                $content = '<div class="help">';
317
                $content .= Display::url(
318
                    Display::return_icon('help.large.png', get_lang('Help')),
319
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
320
                    [
321
                        'class' => 'ajax',
322
                        'data-title' => get_lang('Help'),
323
                    ]
324
                );
325
                $content .= '</div>';
326
            }
327
        }
328
        $this->assign('help_content', $content);
329
    }
330
331
    /**
332
     * Use template system to parse the actions menu.
333
     *
334
     * @todo finish it!
335
     */
336
    public function set_actions($actions)
337
    {
338
        $action_string = '';
339
        if (!empty($actions)) {
340
            foreach ($actions as $action) {
341
                $action_string .= $action;
342
            }
343
        }
344
        $this->assign('actions', $actions);
345
    }
346
347
    /**
348
     * Shortcut to display a 1 col layout (index.php).
349
     * */
350
    public function display_one_col_template(bool $clearFlashMessages = true)
351
    {
352
        $tpl = $this->get_template('layout/layout_1_col.tpl');
353
        $this->display($tpl, $clearFlashMessages);
354
    }
355
356
    /**
357
     * Shortcut to display a 2 col layout (userportal.php).
358
     */
359
    public function display_two_col_template()
360
    {
361
        $tpl = $this->get_template('layout/layout_2_col.tpl');
362
        $this->display($tpl);
363
    }
364
365
    /**
366
     * Displays an empty template.
367
     */
368
    public function display_blank_template()
369
    {
370
        $tpl = $this->get_template('layout/blank.tpl');
371
        $this->display($tpl);
372
    }
373
374
    /**
375
     * Displays an empty template.
376
     */
377
    public function displayBlankTemplateNoHeader()
378
    {
379
        $tpl = $this->get_template('layout/blank_no_header.tpl');
380
        $this->display($tpl);
381
    }
382
383
    /**
384
     * Displays an empty template.
385
     */
386
    public function display_no_layout_template()
387
    {
388
        $tpl = $this->get_template('layout/no_layout.tpl');
389
        $this->display($tpl);
390
    }
391
392
    /**
393
     * Sets the footer visibility.
394
     *
395
     * @param bool true if we show the footer
396
     */
397
    public function set_footer($status)
398
    {
399
        $this->show_footer = $status;
400
        $this->assign('show_footer', $status);
401
    }
402
403
    /**
404
     * return true if toolbar has to be displayed for user.
405
     *
406
     * @return bool
407
     */
408
    public static function isToolBarDisplayedForUser()
409
    {
410
        //Toolbar
411
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
412
        $show_toolbar = false;
413
414
        switch ($show_admin_toolbar) {
415
            case 'do_not_show':
416
                break;
417
            case 'show_to_admin':
418
                if (api_is_platform_admin()) {
419
                    $show_toolbar = true;
420
                }
421
                break;
422
            case 'show_to_admin_and_teachers':
423
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
424
                    $show_toolbar = true;
425
                }
426
                break;
427
            case 'show_to_all':
428
                $show_toolbar = true;
429
                break;
430
        }
431
432
        return $show_toolbar;
433
    }
434
435
    /**
436
     * Sets the header visibility.
437
     *
438
     * @param bool true if we show the header
439
     */
440
    public function set_header($status)
441
    {
442
        $this->show_header = $status;
443
        $this->assign('show_header', $status);
444
445
        $show_toolbar = 0;
446
447
        if (self::isToolBarDisplayedForUser()) {
448
            $show_toolbar = 1;
449
        }
450
451
        $this->assign('show_toolbar', $show_toolbar);
452
453
        // Only if course is available
454
        $courseToolBar = '';
455
        $origin = api_get_origin();
456
        $show_course_navigation_menu = '';
457
        if (!empty($this->course_id) && $this->user_is_logged_in) {
458
            if ($origin !== 'iframe' && $origin !== 'embeddable' && api_get_setting('show_toolshortcuts') !== 'false') {
459
                // Course toolbar
460
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
461
            }
462
            if (api_get_setting('show_navigation_menu') != 'false') {
463
                // Course toolbar
464
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
465
            }
466
        }
467
        $this->assign('show_course_shortcut', $courseToolBar);
468
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
469
    }
470
471
    /**
472
     * Sets an extra class for the main cm-content div.
473
     * To use, give a new row to $htmlContentExtraClass like so: `$htmlContentExtraClass[] = 'feature-item-user-skill-on';`
474
     * before any Display::display_header() call.
475
     */
476
    public function setExtraContentClass($htmlContentExtraClass): void
477
    {
478
        if (empty($htmlContentExtraClass)) {
479
            $extraClass = '';
480
        } else {
481
            if (is_array($htmlContentExtraClass)) {
482
                $extraClass = implode(' ', $htmlContentExtraClass);
483
            } else {
484
                $extraClass = $htmlContentExtraClass;
485
            }
486
            $extraClass = Security::remove_XSS($extraClass);
487
            $extraClass = trim($extraClass);
488
            $extraClass = ' class="'.$extraClass.'"';
489
        }
490
        $this->assign('html_content_extra_class', $extraClass);
491
    }
492
493
    /**
494
     * Returns the sub-folder and filename for the given tpl file.
495
     *
496
     * If template not found in overrides/ or custom template folder, the default template will be used.
497
     *
498
     * @param string $name
499
     *
500
     * @return string
501
     */
502
    public static function findTemplateFilePath($name)
503
    {
504
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
505
506
        // Check if the tpl file is present in the main/template/overrides/ dir
507
        // Overrides is a special directory meant for temporary template
508
        // customization. It must be taken into account before anything else
509
        if (is_readable($sysTemplatePath."overrides/$name")) {
510
            return "overrides/$name";
511
        }
512
513
        $defaultFolder = api_get_configuration_value('default_template');
514
515
        // If a template folder has been manually defined, search for the right
516
        // file, and if not found, go for the same file in the default template
517
        if ($defaultFolder && $defaultFolder != 'default') {
518
            // Avoid missing template error, use the default file.
519
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
520
                return "$defaultFolder/$name";
521
            }
522
        }
523
524
        return "default/$name";
525
    }
526
527
    /**
528
     * Call non-static for Template::findTemplateFilePath.
529
     *
530
     * @see Template::findTemplateFilePath()
531
     *
532
     * @param string $name
533
     *
534
     * @return string
535
     */
536
    public function get_template($name)
537
    {
538
        return api_find_template($name);
539
    }
540
541
    /**
542
     * Get CSS themes sub-directory.
543
     *
544
     * @param string $theme
545
     *
546
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
547
     */
548
    public static function getThemeDir($theme)
549
    {
550
        $themeDir = 'themes/'.$theme.'/';
551
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
552
        if (!empty($virtualTheme)) {
553
            $virtualThemeList = api_get_themes(true);
554
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
555
            if ($isVirtualTheme) {
556
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
557
            }
558
        }
559
560
        return $themeDir;
561
    }
562
563
    /**
564
     * Set system parameters from api_get_configuration into _s array for use in TPLs
565
     * Also fills the _p array from getWebPaths().
566
     *
567
     * @uses \self::getWebPaths()
568
     */
569
    public function set_system_parameters()
570
    {
571
        // Get the interface language from global.inc.php
572
        global $language_interface;
573
        $this->theme = api_get_visual_theme();
574
        if (!empty($this->preview_theme)) {
575
            $this->theme = $this->preview_theme;
576
        }
577
578
        $this->themeDir = self::getThemeDir($this->theme);
579
580
        // Setting app paths/URLs
581
        $this->assign('_p', $this->getWebPaths());
582
583
        // Here we can add system parameters that can be use in any template
584
        $_s = [
585
            'software_name' => api_get_configuration_value('software_name'),
586
            'system_version' => api_get_configuration_value('system_version'),
587
            'site_name' => api_get_setting('siteName'),
588
            'institution' => api_get_setting('Institution'),
589
            'institution_url' => api_get_setting('InstitutionUrl'),
590
            'date' => api_format_date('now', DATE_FORMAT_LONG),
591
            'timezone' => api_get_timezone(),
592
            'gamification_mode' => api_get_setting('gamification_mode'),
593
            'language_interface' => $language_interface,
594
        ];
595
        $this->assign('_s', $_s);
596
    }
597
598
    /**
599
     * Set theme, include mainstream CSS files.
600
     *
601
     * @see setCssCustomFiles() for additional CSS sheets
602
     */
603
    public function setCssFiles()
604
    {
605
        global $disable_js_and_css_files;
606
        $css = [];
607
608
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
609
        $webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
610
611
        // Default CSS Bootstrap
612
        $bowerCSSFiles = [
613
            'fontawesome/css/font-awesome.min.css',
614
            'jquery-ui/themes/smoothness/theme.css',
615
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
616
            'mediaelement/build/mediaelementplayer.min.css',
617
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
618
            'bootstrap/dist/css/bootstrap.min.css',
619
            'jquery.scrollbar/jquery.scrollbar.css',
620
            'bootstrap-daterangepicker/daterangepicker.css',
621
            'bootstrap-select/dist/css/bootstrap-select.min.css',
622
            'select2/dist/css/select2.min.css',
623
        ];
624
625
        $hide = api_get_configuration_value('hide_flag_language_switcher');
626
627
        if ($hide === false) {
628
            $bowerCSSFiles[] = 'flag-icon-css/css/flag-icon.min.css';
629
        }
630
631
        foreach ($bowerCSSFiles as $file) {
632
            $css[] = api_get_cdn_path($webPublicPath.'assets/'.$file);
633
        }
634
635
        $css[] = $webJsPath.'mediaelement/plugins/vrview/vrview.css';
636
637
        $features = api_get_configuration_value('video_features');
638
        $defaultFeatures = [
639
            'playpause',
640
            'current',
641
            'progress',
642
            'duration',
643
            'tracks',
644
            'volume',
645
            'fullscreen',
646
            'vrview',
647
            'markersrolls',
648
        ];
649
650
        if (!empty($features) && isset($features['features'])) {
651
            foreach ($features['features'] as $feature) {
652
                if ($feature === 'vrview') {
653
                    continue;
654
                }
655
                $css[] = $webJsPath."mediaelement/plugins/$feature/$feature.min.css";
656
                $defaultFeatures[] = $feature;
657
            }
658
        }
659
660
        $css[] = $webJsPath.'chosen/chosen.css';
661
662
        if (api_is_global_chat_enabled()) {
663
            $css[] = $webJsPath.'chat/css/chat.css';
664
        }
665
        $css_file_to_string = '';
666
        foreach ($css as $file) {
667
            $css_file_to_string .= api_get_css($file);
668
        }
669
670
        if (!$disable_js_and_css_files) {
671
            $this->assign('css_static_file_to_string', $css_file_to_string);
672
        }
673
674
        $defaultFeatures = implode("','", $defaultFeatures);
675
        $this->assign('video_features', $defaultFeatures);
676
    }
677
678
    /**
679
     * Prepare custom CSS to be added at the very end of the <head> section.
680
     *
681
     * @see setCssFiles() for the mainstream CSS files
682
     */
683
    public function setCssCustomFiles()
684
    {
685
        global $disable_js_and_css_files;
686
        // Base CSS
687
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.css');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$css was never initialized. Although not strictly required by PHP, it is generally a good practice to add $css = array(); before regardless.
Loading history...
688
689
        if ($this->show_learnpath) {
690
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
691
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
692
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
693
            }
694
        }
695
        if (CustomPages::enabled()) {
696
            $cssCustomPage = api_get_path(SYS_CSS_PATH).$this->themeDir."custompage.css";
697
            if (is_file($cssCustomPage)) {
698
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'custompage.css';
699
            } else {
700
                $css[] = api_get_path(WEB_CSS_PATH).'custompage.css';
701
            }
702
        }
703
704
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
705
        $css[] = api_get_cdn_path(ChamiloApi::getEditorBlockStylePath());
706
707
        $css_file_to_string = null;
708
        foreach ($css as $file) {
709
            $css_file_to_string .= api_get_css($file);
710
        }
711
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
712
        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...
713
            //hack in order to fix the actions buttons
714
            $css_file_to_string .= '<style>
715
                .td_actions a {
716
                    float:left;
717
                    width:100%;
718
                }
719
                .forum_message_left a {
720
                    float:left;
721
                    width:100%;
722
                }
723
                </style>';
724
        }
725
726
        $navigator_info = api_get_navigator();
727
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
728
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
729
        }
730
731
        if (!$disable_js_and_css_files) {
732
            $this->assign('css_custom_file_to_string', $css_file_to_string);
733
734
            $style_print = api_get_css(
735
                api_get_print_css(false, true),
736
                'print'
737
            );
738
            $this->assign('css_style_print', $style_print);
739
        }
740
741
        // Logo
742
        $logo = return_logo($this->theme);
743
        $logoPdf = return_logo($this->theme, false);
744
        $this->assign('logo', $logo);
745
        $this->assign('logo_pdf', $logoPdf);
746
        $this->assign('show_media_element', 1);
747
    }
748
749
    /**
750
     * Declare and define the template variable that will be used to load
751
     * javascript libraries in the header.
752
     */
753
    public function set_js_files()
754
    {
755
        global $disable_js_and_css_files, $htmlHeadXtra;
756
        $isoCode = api_get_language_isocode();
757
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
758
759
        if ($isoCode == 'en') {
760
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
761
        }
762
        // JS files
763
        $js_files = [
764
            'chosen/chosen.jquery.min.js',
765
            'mediaelement/plugins/vrview/vrview.js',
766
            'mediaelement/plugins/markersrolls/markersrolls.min.js',
767
        ];
768
769
        if (api_get_setting('accessibility_font_resize') === 'true') {
770
            $js_files[] = 'fontresize.js';
771
        }
772
773
        $js_file_to_string = '';
774
        $bowerJsFiles = [
775
            'modernizr/modernizr.js',
776
            'jquery/dist/jquery.min.js',
777
            'bootstrap/dist/js/bootstrap.min.js',
778
            'jquery-ui/jquery-ui.min.js',
779
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
780
            'moment/min/moment-with-locales.js',
781
            'bootstrap-daterangepicker/daterangepicker.js',
782
            'jquery-timeago/jquery.timeago.js',
783
            'mediaelement/build/mediaelement-and-player.min.js',
784
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
785
            'image-map-resizer/js/imageMapResizer.min.js',
786
            'jquery.scrollbar/jquery.scrollbar.min.js',
787
            'readmore-js/readmore.min.js',
788
            'bootstrap-select/dist/js/bootstrap-select.min.js',
789
            $selectLink,
790
            'select2/dist/js/select2.min.js',
791
            "select2/dist/js/i18n/$isoCode.js",
792
            'js-cookie/src/js.cookie.js',
793
        ];
794
795
        if ($renderers = api_get_configuration_sub_value('video_player_renderers/renderers')) {
796
            foreach ($renderers as $renderName) {
797
                if ('youtube' === $renderName) {
798
                    continue;
799
                }
800
801
                $bowerJsFiles[] = "mediaelement/build/renderers/$renderName.min.js";
802
            }
803
        }
804
805
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
806
807
        if ($viewBySession || api_is_global_chat_enabled()) {
808
            // Do not include the global chat in LP
809
            if ($this->show_learnpath == false &&
810
                $this->show_footer == true &&
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

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

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

Loading history...
812
            ) {
813
                $js_files[] = 'chat/js/chat.js';
814
                $bowerJsFiles[] = 'linkifyjs/linkify.js';
815
                $bowerJsFiles[] = 'linkifyjs/linkify-jquery.js';
816
            }
817
        }
818
819
        $features = api_get_configuration_value('video_features');
820
        if (!empty($features) && isset($features['features'])) {
821
            foreach ($features['features'] as $feature) {
822
                if ($feature === 'vrview') {
823
                    continue;
824
                }
825
                $js_files[] = "mediaelement/plugins/$feature/$feature.min.js";
826
            }
827
        }
828
829
        if (CHAMILO_LOAD_WYSIWYG === true) {
830
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
831
        }
832
833
        if (api_get_setting('include_asciimathml_script') === 'true') {
834
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
835
        }
836
837
        // If not English and the language is supported by timepicker, localize
838
        $assetsPath = api_get_path(SYS_PUBLIC_PATH).'assets/';
839
        if ($isoCode != 'en') {
840
            if (is_file($assetsPath.'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js') && is_file($assetsPath.'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js')) {
841
                $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
842
                $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
843
            }
844
        }
845
846
        foreach ($bowerJsFiles as $file) {
847
            $js_file_to_string .= '<script src="'.api_get_cdn_path(api_get_path(WEB_PUBLIC_PATH).'assets/'.$file).'"></script>'."\n";
848
        }
849
850
        foreach ($js_files as $file) {
851
            $js_file_to_string .= api_get_js($file);
852
        }
853
854
        // Loading email_editor js
855
        if (api_get_setting('allow_email_editor') === 'true') {
856
            $link = 'email_editor.php';
857
            if (!api_is_anonymous()) {
858
                $this->assign('email_editor', $link);
859
                $template = $this->get_template('mail_editor/email_link.js.tpl');
860
                $js_file_to_string .= $this->fetch($template);
861
            } else {
862
                if (api_get_configuration_value('allow_email_editor_for_anonymous')) {
863
                    $link = 'email_editor_external.php';
864
                    $this->assign('email_editor', $link);
865
                    $template = $this->get_template('mail_editor/email_link.js.tpl');
866
                    $js_file_to_string .= $this->fetch($template);
867
                }
868
            }
869
        }
870
871
        if (!$disable_js_and_css_files) {
872
            $this->assign('js_file_to_string', $js_file_to_string);
873
874
            $extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
875
            // Adding jquery ui by default
876
            $extraHeaders .= api_get_jquery_ui_js();
877
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
878
                foreach ($htmlHeadXtra as &$this_html_head) {
879
                    $extraHeaders .= $this_html_head."\n";
880
                }
881
            }
882
883
            $ajax = api_get_path(WEB_AJAX_PATH);
884
            $courseId = api_get_course_id();
885
            if (empty($courseId)) {
886
                $courseLogoutCode = '
887
                <script>
888
                function courseLogout() {
889
                }
890
                </script>';
891
            } else {
892
                $courseLogoutCode = "
893
                <script>
894
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
895
                function courseLogout() {
896
                    $.ajax({
897
                        async : false,
898
                        url: logOutUrl,
899
                        success: function (data) {
900
                            return 1;
901
                        }
902
                    });
903
                }
904
                </script>";
905
            }
906
907
            $extraHeaders .= $courseLogoutCode;
908
            $this->assign('extra_headers', $extraHeaders);
909
        }
910
    }
911
912
    /**
913
     * Special function to declare last-minute JS libraries which depend on
914
     * other things to be declared first. In particular, it might be useful
915
     * under IE9 with compatibility mode, which for some reason is getting
916
     * upset when a variable is used in a function (even if not used yet)
917
     * when this variable hasn't been defined yet.
918
     */
919
    public function set_js_files_post()
920
    {
921
        global $disable_js_and_css_files;
922
        $js_files = [];
923
        $bower = '';
924
        if (api_is_global_chat_enabled()) {
925
            //Do not include the global chat in LP
926
            if ($this->show_learnpath == false && $this->show_footer == true && $this->hide_global_chat == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
927
                $js_files[] = 'chat/js/chat.js';
928
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify.js"></script>';
929
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify-jquery.js"></script>';
930
            }
931
        }
932
        $js_file_to_string = '';
933
        foreach ($js_files as $js_file) {
934
            $js_file_to_string .= api_get_js($js_file);
935
        }
936
        if (!$disable_js_and_css_files) {
937
            $this->assign('js_file_to_string_post', $js_file_to_string.$bower);
938
        }
939
    }
940
941
    /**
942
     * Show header template.
943
     */
944
    public function show_header_template()
945
    {
946
        $tpl = $this->get_template('layout/show_header.tpl');
947
        $this->display($tpl);
948
    }
949
950
    /**
951
     * Show footer template.
952
     */
953
    public function show_footer_template()
954
    {
955
        $tpl = $this->get_template('layout/show_footer.tpl');
956
        $this->display($tpl);
957
    }
958
959
    /**
960
     * Sets the plugin content in a template variable.
961
     *
962
     * @param string $pluginRegion
963
     */
964
    public function set_plugin_region($pluginRegion)
965
    {
966
        if (!empty($pluginRegion)) {
967
            $regionContent = $this->plugin->load_region(
968
                $pluginRegion,
969
                $this,
970
                $this->force_plugin_load
971
            );
972
973
            $pluginList = $this->plugin->getInstalledPlugins(false);
974
            foreach ($pluginList as $plugin_name) {
975
                // The plugin_info variable is available inside the plugin index
976
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
977
978
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
979
                    $courseInfo = api_get_course_info();
980
                    if (!empty($courseInfo)) {
981
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
982
                            /** @var Plugin $plugin */
983
                            $plugin = $pluginInfo['obj'];
984
                            $regionContent .= $plugin->renderRegion($pluginRegion);
985
                        }
986
                    }
987
                } else {
988
                    continue;
989
                }
990
            }
991
992
            if (!empty($regionContent)) {
993
                $this->assign('plugin_'.$pluginRegion, $regionContent);
994
            } else {
995
                $this->assign('plugin_'.$pluginRegion, null);
996
            }
997
        }
998
999
        return null;
1000
    }
1001
1002
    /**
1003
     * @param string $template
1004
     *
1005
     * @return string
1006
     */
1007
    public function fetch($template = null)
1008
    {
1009
        $template = $this->twig->loadTemplate($template);
1010
1011
        return $template->render($this->params);
1012
    }
1013
1014
    /**
1015
     * @param string $variable
1016
     * @param mixed  $value
1017
     */
1018
    public function assign($variable, $value = '')
1019
    {
1020
        $this->params[$variable] = $value;
1021
    }
1022
1023
    /**
1024
     * Render the template.
1025
     *
1026
     * @param string $template           The template path
1027
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
1028
     */
1029
    public function display($template, $clearFlashMessages = true)
1030
    {
1031
        $this->assign('page_origin', api_get_origin());
1032
        $this->assign('flash_messages', Display::getFlashToString());
1033
1034
        if ($clearFlashMessages) {
1035
            Display::cleanFlashMessages();
1036
        }
1037
1038
        echo $this->twig->render($template, $this->params);
1039
    }
1040
1041
    /**
1042
     * Adds a body class for login pages.
1043
     */
1044
    public function setLoginBodyClass()
1045
    {
1046
        $this->assign('login_class', 'section-login');
1047
    }
1048
1049
    /**
1050
     * The theme that will be used if the database is not working.
1051
     *
1052
     * @return string
1053
     */
1054
    public static function getThemeFallback()
1055
    {
1056
        $theme = api_get_configuration_value('theme_fallback');
1057
        if (empty($theme)) {
1058
            $theme = 'chamilo';
1059
        }
1060
1061
        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...
1062
    }
1063
1064
    /**
1065
     * @param bool|true $setLoginForm
1066
     */
1067
    public function setLoginForm($setLoginForm = true)
1068
    {
1069
        global $loginFailed;
1070
        $userId = api_get_user_id();
1071
        if (!($userId) || api_is_anonymous($userId)) {
1072
            // Only display if the user isn't logged in.
1073
            $this->assign(
1074
                'login_language_form',
1075
                api_display_language_form(true, true)
1076
            );
1077
            if ($setLoginForm) {
1078
                $this->assign('login_form', $this->displayLoginForm());
1079
1080
                if ($loginFailed) {
1081
                    $this->assign('login_failed', $this::handleLoginFailed());
0 ignored issues
show
Bug Best Practice introduced by
The method Template::handleLoginFailed() is not static, but was called statically. ( Ignorable by Annotation )

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

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

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

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

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

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