Passed
Push — 1.11.x ( 6c626e...925e49 )
by Yannick
10:39 queued 15s
created

Template::setCssFiles()   C

Complexity

Conditions 12
Paths 256

Size

Total Lines 80
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 51
c 0
b 0
f 0
dl 0
loc 80
rs 5.4333
cc 12
nc 256
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
        $isVrViewEnabled = Display::isVrViewEnabled();
636
637
        if ($isVrViewEnabled) {
638
            $css[] = $webJsPath.'mediaelement/plugins/vrview/vrview.css';
639
        }
640
641
        $features = api_get_configuration_value('video_features');
642
        $defaultFeatures = [
643
            'playpause',
644
            'current',
645
            'progress',
646
            'duration',
647
            'tracks',
648
            'volume',
649
            'fullscreen',
650
            'markersrolls',
651
        ];
652
653
        if ($isVrViewEnabled) {
654
            $defaultFeatures[] = 'vrview';
655
        }
656
657
        if (!empty($features) && isset($features['features'])) {
658
            foreach ($features['features'] as $feature) {
659
                if ($feature === 'vrview') {
660
                    continue;
661
                }
662
                $css[] = $webJsPath."mediaelement/plugins/$feature/$feature.min.css";
663
                $defaultFeatures[] = $feature;
664
            }
665
        }
666
667
        $css[] = $webJsPath.'chosen/chosen.css';
668
669
        if (api_is_global_chat_enabled()) {
670
            $css[] = $webJsPath.'chat/css/chat.css';
671
        }
672
        $css_file_to_string = '';
673
        foreach ($css as $file) {
674
            $css_file_to_string .= api_get_css($file);
675
        }
676
677
        if (!$disable_js_and_css_files) {
678
            $this->assign('css_static_file_to_string', $css_file_to_string);
679
        }
680
681
        $defaultFeatures = implode("','", $defaultFeatures);
682
        $this->assign('video_features', $defaultFeatures);
683
    }
684
685
    /**
686
     * Prepare custom CSS to be added at the very end of the <head> section.
687
     *
688
     * @see setCssFiles() for the mainstream CSS files
689
     */
690
    public function setCssCustomFiles()
691
    {
692
        global $disable_js_and_css_files;
693
        // Base CSS
694
        $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...
695
696
        if ($this->show_learnpath) {
697
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
698
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
699
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
700
            }
701
        }
702
        if (CustomPages::enabled()) {
703
            $cssCustomPage = api_get_path(SYS_CSS_PATH).$this->themeDir."custompage.css";
704
            if (is_file($cssCustomPage)) {
705
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'custompage.css';
706
            } else {
707
                $css[] = api_get_path(WEB_CSS_PATH).'custompage.css';
708
            }
709
        }
710
711
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
712
        $css[] = api_get_cdn_path(ChamiloApi::getEditorBlockStylePath());
713
714
        $css_file_to_string = null;
715
        foreach ($css as $file) {
716
            $css_file_to_string .= api_get_css($file);
717
        }
718
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
719
        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...
720
            //hack in order to fix the actions buttons
721
            $css_file_to_string .= '<style>
722
                .td_actions a {
723
                    float:left;
724
                    width:100%;
725
                }
726
                .forum_message_left a {
727
                    float:left;
728
                    width:100%;
729
                }
730
                </style>';
731
        }
732
733
        $navigator_info = api_get_navigator();
734
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
735
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
736
        }
737
738
        if (!$disable_js_and_css_files) {
739
            $this->assign('css_custom_file_to_string', $css_file_to_string);
740
741
            $style_print = api_get_css(
742
                api_get_print_css(false, true),
743
                'print'
744
            );
745
            $this->assign('css_style_print', $style_print);
746
        }
747
748
        // Logo
749
        $logo = return_logo($this->theme);
750
        $logoPdf = return_logo($this->theme, false);
751
        $this->assign('logo', $logo);
752
        $this->assign('logo_pdf', $logoPdf);
753
        $this->assign('show_media_element', 1);
754
    }
755
756
    /**
757
     * Declare and define the template variable that will be used to load
758
     * javascript libraries in the header.
759
     */
760
    public function set_js_files()
761
    {
762
        global $disable_js_and_css_files, $htmlHeadXtra;
763
        $isoCode = api_get_language_isocode();
764
        $isVrViewEnabled = Display::isVrViewEnabled();
765
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
766
767
        if ($isoCode == 'en') {
768
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
769
        }
770
        // JS files
771
        $js_files = [];
772
        $js_files[] = 'chosen/chosen.jquery.min.js';
773
774
        if ($isVrViewEnabled) {
775
            $js_files[] = 'mediaelement/plugins/vrview/vrview.js';
776
        }
777
778
        $js_files[] = 'mediaelement/plugins/markersrolls/markersrolls.min.js';
779
780
        if (api_get_setting('accessibility_font_resize') === 'true') {
781
            $js_files[] = 'fontresize.js';
782
        }
783
784
        $js_file_to_string = '';
785
        $bowerJsFiles = [
786
            'modernizr/modernizr.js',
787
            'jquery/dist/jquery.min.js',
788
            'bootstrap/dist/js/bootstrap.min.js',
789
            'jquery-ui/jquery-ui.min.js',
790
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
791
            'moment/min/moment-with-locales.js',
792
            'bootstrap-daterangepicker/daterangepicker.js',
793
            'jquery-timeago/jquery.timeago.js',
794
            'mediaelement/build/mediaelement-and-player.min.js',
795
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
796
            'image-map-resizer/js/imageMapResizer.min.js',
797
            'jquery.scrollbar/jquery.scrollbar.min.js',
798
            'readmore-js/readmore.min.js',
799
            'bootstrap-select/dist/js/bootstrap-select.min.js',
800
            $selectLink,
801
            'select2/dist/js/select2.min.js',
802
            "select2/dist/js/i18n/$isoCode.js",
803
            'js-cookie/src/js.cookie.js',
804
        ];
805
806
        if ($renderers = api_get_configuration_sub_value('video_player_renderers/renderers')) {
807
            foreach ($renderers as $renderName) {
808
                if ('youtube' === $renderName) {
809
                    continue;
810
                }
811
812
                $bowerJsFiles[] = "mediaelement/build/renderers/$renderName.min.js";
813
            }
814
        }
815
816
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
817
818
        if ($viewBySession || api_is_global_chat_enabled()) {
819
            // Do not include the global chat in LP
820
            if ($this->show_learnpath == false &&
821
                $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...
822
                $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...
823
            ) {
824
                $js_files[] = 'chat/js/chat.js';
825
                $bowerJsFiles[] = 'linkifyjs/linkify.js';
826
                $bowerJsFiles[] = 'linkifyjs/linkify-jquery.js';
827
            }
828
        }
829
830
        $features = api_get_configuration_value('video_features');
831
        if (!empty($features) && isset($features['features'])) {
832
            foreach ($features['features'] as $feature) {
833
                if ($feature === 'vrview') {
834
                    continue;
835
                }
836
                $js_files[] = "mediaelement/plugins/$feature/$feature.min.js";
837
            }
838
        }
839
840
        if (CHAMILO_LOAD_WYSIWYG === true) {
841
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
842
        }
843
844
        if (api_get_setting('include_asciimathml_script') === 'true') {
845
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
846
        }
847
848
        // If not English and the language is supported by timepicker, localize
849
        $assetsPath = api_get_path(SYS_PUBLIC_PATH).'assets/';
850
        if ($isoCode != 'en') {
851
            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')) {
852
                $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
853
                $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
854
            }
855
        }
856
857
        foreach ($bowerJsFiles as $file) {
858
            $js_file_to_string .= '<script src="'.api_get_cdn_path(api_get_path(WEB_PUBLIC_PATH).'assets/'.$file).'"></script>'."\n";
859
        }
860
861
        foreach ($js_files as $file) {
862
            $js_file_to_string .= api_get_js($file);
863
        }
864
865
        // Loading email_editor js
866
        if (api_get_setting('allow_email_editor') === 'true') {
867
            $link = 'email_editor.php';
868
            if (!api_is_anonymous()) {
869
                $this->assign('email_editor', $link);
870
                $template = $this->get_template('mail_editor/email_link.js.tpl');
871
                $js_file_to_string .= $this->fetch($template);
872
            } else {
873
                if (api_get_configuration_value('allow_email_editor_for_anonymous')) {
874
                    $link = 'email_editor_external.php';
875
                    $this->assign('email_editor', $link);
876
                    $template = $this->get_template('mail_editor/email_link.js.tpl');
877
                    $js_file_to_string .= $this->fetch($template);
878
                }
879
            }
880
        }
881
882
        if (!$disable_js_and_css_files) {
883
            $this->assign('js_file_to_string', $js_file_to_string);
884
885
            $extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
886
            // Adding jquery ui by default
887
            $extraHeaders .= api_get_jquery_ui_js();
888
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
889
                foreach ($htmlHeadXtra as &$this_html_head) {
890
                    $extraHeaders .= $this_html_head."\n";
891
                }
892
            }
893
894
            $ajax = api_get_path(WEB_AJAX_PATH);
895
            $courseId = api_get_course_id();
896
            if (empty($courseId)) {
897
                $courseLogoutCode = '
898
                <script>
899
                function courseLogout() {
900
                }
901
                </script>';
902
            } else {
903
                $courseLogoutCode = "
904
                <script>
905
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
906
                function courseLogout() {
907
                    $.ajax({
908
                        async : false,
909
                        url: logOutUrl,
910
                        success: function (data) {
911
                            return 1;
912
                        }
913
                    });
914
                }
915
                </script>";
916
            }
917
918
            $extraHeaders .= $courseLogoutCode;
919
            $this->assign('extra_headers', $extraHeaders);
920
        }
921
    }
922
923
    /**
924
     * Special function to declare last-minute JS libraries which depend on
925
     * other things to be declared first. In particular, it might be useful
926
     * under IE9 with compatibility mode, which for some reason is getting
927
     * upset when a variable is used in a function (even if not used yet)
928
     * when this variable hasn't been defined yet.
929
     */
930
    public function set_js_files_post()
931
    {
932
        global $disable_js_and_css_files;
933
        $js_files = [];
934
        $bower = '';
935
        if (api_is_global_chat_enabled()) {
936
            //Do not include the global chat in LP
937
            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...
938
                $js_files[] = 'chat/js/chat.js';
939
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify.js"></script>';
940
                $bower .= '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify-jquery.js"></script>';
941
            }
942
        }
943
        $js_file_to_string = '';
944
        foreach ($js_files as $js_file) {
945
            $js_file_to_string .= api_get_js($js_file);
946
        }
947
        if (!$disable_js_and_css_files) {
948
            $this->assign('js_file_to_string_post', $js_file_to_string.$bower);
949
        }
950
    }
951
952
    /**
953
     * Show header template.
954
     */
955
    public function show_header_template()
956
    {
957
        $tpl = $this->get_template('layout/show_header.tpl');
958
        $this->display($tpl);
959
    }
960
961
    /**
962
     * Show footer template.
963
     */
964
    public function show_footer_template()
965
    {
966
        $tpl = $this->get_template('layout/show_footer.tpl');
967
        $this->display($tpl);
968
    }
969
970
    /**
971
     * Sets the plugin content in a template variable.
972
     *
973
     * @param string $pluginRegion
974
     */
975
    public function set_plugin_region($pluginRegion)
976
    {
977
        if (!empty($pluginRegion)) {
978
            $regionContent = $this->plugin->load_region(
979
                $pluginRegion,
980
                $this,
981
                $this->force_plugin_load
982
            );
983
984
            $pluginList = $this->plugin->getInstalledPlugins(false);
985
            foreach ($pluginList as $plugin_name) {
986
                // The plugin_info variable is available inside the plugin index
987
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
988
989
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
990
                    $courseInfo = api_get_course_info();
991
                    if (!empty($courseInfo)) {
992
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
993
                            /** @var Plugin $plugin */
994
                            $plugin = $pluginInfo['obj'];
995
                            $regionContent .= $plugin->renderRegion($pluginRegion);
996
                        }
997
                    }
998
                } else {
999
                    continue;
1000
                }
1001
            }
1002
1003
            if (!empty($regionContent)) {
1004
                $this->assign('plugin_'.$pluginRegion, $regionContent);
1005
            } else {
1006
                $this->assign('plugin_'.$pluginRegion, null);
1007
            }
1008
        }
1009
1010
        return null;
1011
    }
1012
1013
    /**
1014
     * @param string $template
1015
     *
1016
     * @return string
1017
     */
1018
    public function fetch($template = null)
1019
    {
1020
        $template = $this->twig->loadTemplate($template);
1021
1022
        return $template->render($this->params);
1023
    }
1024
1025
    /**
1026
     * @param string $variable
1027
     * @param mixed  $value
1028
     */
1029
    public function assign($variable, $value = '')
1030
    {
1031
        $this->params[$variable] = $value;
1032
    }
1033
1034
    /**
1035
     * Render the template.
1036
     *
1037
     * @param string $template           The template path
1038
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
1039
     */
1040
    public function display($template, $clearFlashMessages = true)
1041
    {
1042
        $this->assign('page_origin', api_get_origin());
1043
        $this->assign('flash_messages', Display::getFlashToString());
1044
1045
        if ($clearFlashMessages) {
1046
            Display::cleanFlashMessages();
1047
        }
1048
1049
        echo $this->twig->render($template, $this->params);
1050
    }
1051
1052
    /**
1053
     * Adds a body class for login pages.
1054
     */
1055
    public function setLoginBodyClass()
1056
    {
1057
        $this->assign('login_class', 'section-login');
1058
    }
1059
1060
    /**
1061
     * The theme that will be used if the database is not working.
1062
     *
1063
     * @return string
1064
     */
1065
    public static function getThemeFallback()
1066
    {
1067
        $theme = api_get_configuration_value('theme_fallback');
1068
        if (empty($theme)) {
1069
            $theme = 'chamilo';
1070
        }
1071
1072
        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...
1073
    }
1074
1075
    /**
1076
     * @param bool|true $setLoginForm
1077
     */
1078
    public function setLoginForm($setLoginForm = true)
1079
    {
1080
        global $loginFailed;
1081
        $userId = api_get_user_id();
1082
        if (!($userId) || api_is_anonymous($userId)) {
1083
            // Only display if the user isn't logged in.
1084
            $this->assign(
1085
                'login_language_form',
1086
                api_display_language_form(true, true)
1087
            );
1088
            if ($setLoginForm) {
1089
                $this->assign('login_form', $this->displayLoginForm());
1090
1091
                if ($loginFailed) {
1092
                    $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

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

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

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