Passed
Push — webservicelpcreate ( d8cb35 )
by
unknown
13:48
created

Template   F

Complexity

Total Complexity 273

Size/Duplication

Total Lines 2010
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 1017
dl 0
loc 2010
rs 1.532
c 0
b 0
f 0
wmc 273

49 Methods

Rating   Name   Duplication   Size   Complexity  
A show_footer_template() 0 4 1
A fetch() 0 5 1
B set_plugin_region() 0 36 9
A assign() 0 3 1
A show_header_template() 0 4 1
A set_footer() 0 4 1
F __construct() 0 197 18
A key() 0 17 6
A get_template() 0 3 1
A displayBlankTemplateNoHeader() 0 4 1
B isToolBarDisplayedForUser() 0 25 8
A display_two_col_template() 0 4 1
A display_blank_template() 0 4 1
A display_one_col_template() 0 4 1
A findTemplateFilePath() 0 23 5
A setHelp() 0 25 4
A getThemeDir() 0 13 3
A set_actions() 0 9 3
A set_header() 0 28 6
A display_no_layout_template() 0 4 1
B setCssFiles() 0 73 10
C displayLoginForm() 0 123 11
A getWebPaths() 0 24 3
A display() 0 10 2
F set_header_parameters() 0 170 25
F set_footer_parameters() 0 89 21
A set_course_parameters() 0 24 3
A displayCASLoginButton() 0 22 2
A setAdministratorParams() 0 10 1
B set_js_files_post() 0 19 7
A getResponseCode() 0 3 1
A setLoginBodyClass() 0 3 1
A assignAccessibilityBlock() 0 15 2
A returnTutorsNames() 0 24 2
A setResponseCode() 0 3 1
F assignSocialMeta() 0 93 17
D addHTTPSecurityHeaders() 0 47 10
A set_user_parameters() 0 19 3
A set_system_parameters() 0 27 2
B setCssCustomFiles() 0 59 9
A getThemeFallback() 0 8 2
A getMetaPortalImagePath() 0 23 4
A setLoginForm() 0 15 5
B assignBugNotification() 0 50 7
C handleLoginFailed() 0 52 14
A returnTeachersNames() 0 23 2
A assignFavIcon() 0 35 5
A displayCASLogoutButton() 0 21 2
F set_js_files() 0 135 26

How to fix   Complexity   

Complex Class

Complex classes like Template often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Template, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
5
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
6
use Chamilo\UserBundle\Entity\User;
7
8
/**
9
 * Class Template.
10
 *
11
 * @author Julio Montoya <[email protected]>
12
 *
13
 * @todo better organization of the class, methods and variables
14
 */
15
class Template
16
{
17
    /**
18
     * The Template folder name see main/template.
19
     *
20
     * @var string
21
     */
22
    public $templateFolder = 'default';
23
24
    /**
25
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
26
     * This variable is set from the database.
27
     *
28
     * @var string
29
     */
30
    public $theme = '';
31
32
    /**
33
     * @var string
34
     */
35
    public $preview_theme = '';
36
    public $title = null;
37
    public $show_header;
38
    public $show_footer;
39
    public $help;
40
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
41
    public $show_learnpath = false; // This is a learnpath section or not?
42
    public $plugin = null;
43
    public $course_id = null;
44
    public $user_is_logged_in = false;
45
    public $twig = null;
46
47
    /* Loads chamilo plugins */
48
    public $load_plugins = false;
49
    public $params = [];
50
    public $force_plugin_load = false;
51
    public $responseCode = 0;
52
    private $themeDir;
53
54
    /**
55
     * @param string $title
56
     * @param bool   $show_header
57
     * @param bool   $show_footer
58
     * @param bool   $show_learnpath
59
     * @param bool   $hide_global_chat
60
     * @param bool   $load_plugins
61
     * @param int    $responseCode
62
     * @param bool   $sendHeaders      send http headers or not
63
     */
64
    public function __construct(
65
        $title = '',
66
        $show_header = true,
67
        $show_footer = true,
68
        $show_learnpath = false,
69
        $hide_global_chat = false,
70
        $load_plugins = true,
71
        $sendHeaders = true,
72
        $responseCode = 0
73
    ) {
74
        // Page title
75
        $this->title = $title;
76
        $this->show_learnpath = $show_learnpath;
77
        $this->setResponseCode($responseCode);
78
79
        if (empty($this->show_learnpath)) {
80
            $origin = api_get_origin();
81
            if ($origin === 'learnpath') {
82
                $this->show_learnpath = true;
83
                $show_footer = false;
84
                $show_header = false;
85
            }
86
        }
87
        $this->hide_global_chat = $hide_global_chat;
88
        $this->load_plugins = $load_plugins;
89
90
        $template_paths = [
91
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
92
            api_get_path(SYS_CODE_PATH).'template', //template folder
93
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
94
        ];
95
96
        $urlId = api_get_current_access_url_id();
97
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
98
99
        if (!is_dir($cache_folder)) {
100
            mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
101
        }
102
103
        $loader = new Twig_Loader_Filesystem($template_paths);
104
105
        $isTestMode = api_get_setting('server_type') === 'test';
106
107
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
108
        if ($isTestMode) {
109
            $options = [
110
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
111
                'autoescape' => false,
112
                'debug' => true,
113
                'auto_reload' => true,
114
                'optimizations' => 0,
115
                // turn on optimizations with -1
116
                'strict_variables' => false,
117
                //If set to false, Twig will silently ignore invalid variables
118
            ];
119
        } else {
120
            $options = [
121
                'cache' => $cache_folder,
122
                //path to the cache folder
123
                'autoescape' => false,
124
                'debug' => false,
125
                'auto_reload' => false,
126
                'optimizations' => -1,
127
                // turn on optimizations with -1
128
                'strict_variables' => false,
129
                //If set to false, Twig will silently ignore invalid variables
130
            ];
131
        }
132
133
        $this->twig = new Twig_Environment($loader, $options);
134
135
        if ($isTestMode) {
136
            $this->twig->addExtension(new Twig_Extension_Debug());
137
        }
138
139
        // Twig filters setup
140
        $filters = [
141
            'var_dump',
142
            'get_plugin_lang',
143
            'get_lang',
144
            'api_get_path',
145
            'api_get_local_time',
146
            'api_convert_and_format_date',
147
            'api_is_allowed_to_edit',
148
            'api_get_user_info',
149
            'api_get_configuration_value',
150
            'api_get_setting',
151
            'api_get_plugin_setting',
152
            [
153
                'name' => 'return_message',
154
                'callable' => 'Display::return_message_and_translate',
155
            ],
156
            [
157
                'name' => 'display_page_header',
158
                'callable' => 'Display::page_header_and_translate',
159
            ],
160
            [
161
                'name' => 'display_page_subheader',
162
                'callable' => 'Display::page_subheader_and_translate',
163
            ],
164
            [
165
                'name' => 'icon',
166
                'callable' => 'Display::get_icon_path',
167
            ],
168
            [
169
                'name' => 'img',
170
                'callable' => 'Display::get_image',
171
            ],
172
            [
173
                'name' => 'format_date',
174
                'callable' => 'api_format_date',
175
            ],
176
            [
177
                'name' => 'get_template',
178
                'callable' => 'api_find_template',
179
            ],
180
            [
181
                'name' => 'date_to_time_ago',
182
                'callable' => 'Display::dateToStringAgoAndLongDate',
183
            ],
184
            [
185
                'name' => 'remove_xss',
186
                'callable' => 'Security::remove_XSS',
187
            ],
188
        ];
189
190
        foreach ($filters as $filter) {
191
            if (is_array($filter)) {
192
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
193
            } else {
194
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
195
            }
196
        }
197
198
        $functions = [
199
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
200
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
201
        ];
202
203
        foreach ($functions as $function) {
204
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
205
        }
206
207
        // Setting system variables
208
        $this->set_system_parameters();
209
210
        // Setting user variables
211
        $this->set_user_parameters();
212
213
        // Setting course variables
214
        $this->set_course_parameters();
215
216
        // Setting administrator variables
217
        $this->setAdministratorParams();
218
        //$this->setCSSEditor();
219
220
        // Header and footer are showed by default
221
        $this->set_footer($show_footer);
222
        $this->set_header($show_header);
223
224
        $this->set_header_parameters($sendHeaders);
225
        $this->set_footer_parameters();
226
227
        $defaultStyle = api_get_configuration_value('default_template');
228
        if (!empty($defaultStyle)) {
229
            $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...
230
        }
231
232
        $this->assign('template', $this->templateFolder);
233
        $this->assign('locale', api_get_language_isocode());
234
        $this->assign('login_class', null);
235
236
        $allow = api_get_configuration_value('show_language_selector_in_menu');
237
        if ($allow) {
238
            $this->assign('language_form', api_display_language_form());
239
        }
240
241
        if (api_get_configuration_value('notification_event')) {
242
            $this->assign('notification_event', '1');
243
        }
244
245
        // Chamilo plugins
246
        if ($this->show_header) {
247
            if ($this->load_plugins) {
248
                $this->plugin = new AppPlugin();
249
250
                //1. Showing installed plugins in regions
251
                $pluginRegions = $this->plugin->get_plugin_regions();
252
                foreach ($pluginRegions as $region) {
253
                    $this->set_plugin_region($region);
254
                }
255
256
                //2. Loading the course plugin info
257
                global $course_plugin;
258
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
259
                    //Load plugin get_langs
260
                    $this->plugin->load_plugin_lang_variables($course_plugin);
261
                }
262
            }
263
        }
264
    }
265
266
    /**
267
     * Return the item's url key:.
268
     *
269
     *      c_id=xx&id=xx
270
     *
271
     * @param object $item
272
     *
273
     * @return string
274
     */
275
    public static function key($item)
276
    {
277
        $id = isset($item->id) ? $item->id : null;
278
        $c_id = isset($item->c_id) ? $item->c_id : null;
279
        $result = '';
280
        if ($c_id) {
281
            $result = "c_id=$c_id";
282
        }
283
        if ($id) {
284
            if ($result) {
285
                $result .= "&amp;id=$id";
286
            } else {
287
                $result .= "&amp;id=$id";
288
            }
289
        }
290
291
        return $result;
292
    }
293
294
    /**
295
     * @param string $helpInput
296
     */
297
    public function setHelp($helpInput = null)
298
    {
299
        if (!empty($helpInput)) {
300
            $help = $helpInput;
301
        } else {
302
            $help = $this->help;
303
        }
304
305
        $content = '';
306
        if (api_get_setting('enable_help_link') == 'true') {
307
            if (!empty($help)) {
308
                $help = Security::remove_XSS($help);
309
                $content = '<div class="help">';
310
                $content .= Display::url(
311
                    Display::return_icon('help.large.png', get_lang('Help')),
312
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
313
                    [
314
                        'class' => 'ajax',
315
                        'data-title' => get_lang('Help'),
316
                    ]
317
                );
318
                $content .= '</div>';
319
            }
320
        }
321
        $this->assign('help_content', $content);
322
    }
323
324
    /**
325
     * Use template system to parse the actions menu.
326
     *
327
     * @todo finish it!
328
     */
329
    public function set_actions($actions)
330
    {
331
        $action_string = '';
332
        if (!empty($actions)) {
333
            foreach ($actions as $action) {
334
                $action_string .= $action;
335
            }
336
        }
337
        $this->assign('actions', $actions);
338
    }
339
340
    /**
341
     * Shortcut to display a 1 col layout (index.php).
342
     * */
343
    public function display_one_col_template()
344
    {
345
        $tpl = $this->get_template('layout/layout_1_col.tpl');
346
        $this->display($tpl);
347
    }
348
349
    /**
350
     * Shortcut to display a 2 col layout (userportal.php).
351
     */
352
    public function display_two_col_template()
353
    {
354
        $tpl = $this->get_template('layout/layout_2_col.tpl');
355
        $this->display($tpl);
356
    }
357
358
    /**
359
     * Displays an empty template.
360
     */
361
    public function display_blank_template()
362
    {
363
        $tpl = $this->get_template('layout/blank.tpl');
364
        $this->display($tpl);
365
    }
366
367
    /**
368
     * Displays an empty template.
369
     */
370
    public function displayBlankTemplateNoHeader()
371
    {
372
        $tpl = $this->get_template('layout/blank_no_header.tpl');
373
        $this->display($tpl);
374
    }
375
376
    /**
377
     * Displays an empty template.
378
     */
379
    public function display_no_layout_template()
380
    {
381
        $tpl = $this->get_template('layout/no_layout.tpl');
382
        $this->display($tpl);
383
    }
384
385
    /**
386
     * Sets the footer visibility.
387
     *
388
     * @param bool true if we show the footer
389
     */
390
    public function set_footer($status)
391
    {
392
        $this->show_footer = $status;
393
        $this->assign('show_footer', $status);
394
    }
395
396
    /**
397
     * return true if toolbar has to be displayed for user.
398
     *
399
     * @return bool
400
     */
401
    public static function isToolBarDisplayedForUser()
402
    {
403
        //Toolbar
404
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
405
        $show_toolbar = false;
406
407
        switch ($show_admin_toolbar) {
408
            case 'do_not_show':
409
                break;
410
            case 'show_to_admin':
411
                if (api_is_platform_admin()) {
412
                    $show_toolbar = true;
413
                }
414
                break;
415
            case 'show_to_admin_and_teachers':
416
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
417
                    $show_toolbar = true;
418
                }
419
                break;
420
            case 'show_to_all':
421
                $show_toolbar = true;
422
                break;
423
        }
424
425
        return $show_toolbar;
426
    }
427
428
    /**
429
     * Sets the header visibility.
430
     *
431
     * @param bool true if we show the header
432
     */
433
    public function set_header($status)
434
    {
435
        $this->show_header = $status;
436
        $this->assign('show_header', $status);
437
438
        $show_toolbar = 0;
439
440
        if (self::isToolBarDisplayedForUser()) {
441
            $show_toolbar = 1;
442
        }
443
444
        $this->assign('show_toolbar', $show_toolbar);
445
446
        // Only if course is available
447
        $courseToolBar = '';
448
        $show_course_navigation_menu = '';
449
        if (!empty($this->course_id) && $this->user_is_logged_in) {
450
            if (api_get_setting('show_toolshortcuts') != 'false') {
451
                // Course toolbar
452
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
453
            }
454
            if (api_get_setting('show_navigation_menu') != 'false') {
455
                // Course toolbar
456
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
457
            }
458
        }
459
        $this->assign('show_course_shortcut', $courseToolBar);
460
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
461
    }
462
463
    /**
464
     * Returns the sub-folder and filename for the given tpl file.
465
     *
466
     * If template not found in overrides/ or custom template folder, the default template will be used.
467
     *
468
     * @param string $name
469
     *
470
     * @return string
471
     */
472
    public static function findTemplateFilePath($name)
473
    {
474
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
475
476
        // Check if the tpl file is present in the main/template/overrides/ dir
477
        // Overrides is a special directory meant for temporary template
478
        // customization. It must be taken into account before anything else
479
        if (is_readable($sysTemplatePath."overrides/$name")) {
480
            return "overrides/$name";
481
        }
482
483
        $defaultFolder = api_get_configuration_value('default_template');
484
485
        // If a template folder has been manually defined, search for the right
486
        // file, and if not found, go for the same file in the default template
487
        if ($defaultFolder && $defaultFolder != 'default') {
488
            // Avoid missing template error, use the default file.
489
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
490
                return "$defaultFolder/$name";
491
            }
492
        }
493
494
        return "default/$name";
495
    }
496
497
    /**
498
     * Call non-static for Template::findTemplateFilePath.
499
     *
500
     * @see Template::findTemplateFilePath()
501
     *
502
     * @param string $name
503
     *
504
     * @return string
505
     */
506
    public function get_template($name)
507
    {
508
        return api_find_template($name);
509
    }
510
511
    /**
512
     * Get CSS themes sub-directory.
513
     *
514
     * @param string $theme
515
     *
516
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
517
     */
518
    public static function getThemeDir($theme)
519
    {
520
        $themeDir = 'themes/'.$theme.'/';
521
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
522
        if (!empty($virtualTheme)) {
523
            $virtualThemeList = api_get_themes(true);
524
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
525
            if ($isVirtualTheme) {
526
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
527
            }
528
        }
529
530
        return $themeDir;
531
    }
532
533
    /**
534
     * Set system parameters from api_get_configuration into _s array for use in TPLs
535
     * Also fills the _p array from getWebPaths().
536
     *
537
     * @uses \self::getWebPaths()
538
     */
539
    public function set_system_parameters()
540
    {
541
        // Get the interface language from global.inc.php
542
        global $language_interface;
543
        $this->theme = api_get_visual_theme();
544
        if (!empty($this->preview_theme)) {
545
            $this->theme = $this->preview_theme;
546
        }
547
548
        $this->themeDir = self::getThemeDir($this->theme);
549
550
        // Setting app paths/URLs
551
        $this->assign('_p', $this->getWebPaths());
552
553
        // Here we can add system parameters that can be use in any template
554
        $_s = [
555
            'software_name' => api_get_configuration_value('software_name'),
556
            'system_version' => api_get_configuration_value('system_version'),
557
            'site_name' => api_get_setting('siteName'),
558
            'institution' => api_get_setting('Institution'),
559
            'institution_url' => api_get_setting('InstitutionUrl'),
560
            'date' => api_format_date('now', DATE_FORMAT_LONG),
561
            'timezone' => api_get_timezone(),
562
            'gamification_mode' => api_get_setting('gamification_mode'),
563
            'language_interface' => $language_interface,
564
        ];
565
        $this->assign('_s', $_s);
566
    }
567
568
    /**
569
     * Set theme, include mainstream CSS files.
570
     *
571
     * @see setCssCustomFiles() for additional CSS sheets
572
     */
573
    public function setCssFiles()
574
    {
575
        global $disable_js_and_css_files;
576
        $css = [];
577
578
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
579
        $webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
580
581
        // Default CSS Bootstrap
582
        $bowerCSSFiles = [
583
            'fontawesome/css/font-awesome.min.css',
584
            'jquery-ui/themes/smoothness/theme.css',
585
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
586
            'mediaelement/build/mediaelementplayer.min.css',
587
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
588
            'bootstrap/dist/css/bootstrap.min.css',
589
            'jquery.scrollbar/jquery.scrollbar.css',
590
            'bootstrap-daterangepicker/daterangepicker.css',
591
            'bootstrap-select/dist/css/bootstrap-select.min.css',
592
            'select2/dist/css/select2.min.css',
593
        ];
594
595
        $hide = api_get_configuration_value('hide_flag_language_switcher');
596
597
        if ($hide === false) {
598
            $bowerCSSFiles[] = 'flag-icon-css/css/flag-icon.min.css';
599
        }
600
601
        foreach ($bowerCSSFiles as $file) {
602
            $css[] = api_get_cdn_path($webPublicPath.'assets/'.$file);
603
        }
604
605
        $css[] = $webJsPath.'mediaelement/plugins/vrview/vrview.css';
606
607
        $features = api_get_configuration_value('video_features');
608
        $defaultFeatures = [
609
            'playpause',
610
            'current',
611
            'progress',
612
            'duration',
613
            'tracks',
614
            'volume',
615
            'fullscreen',
616
            'vrview',
617
            'markersrolls',
618
        ];
619
620
        if (!empty($features) && isset($features['features'])) {
621
            foreach ($features['features'] as $feature) {
622
                if ($feature === 'vrview') {
623
                    continue;
624
                }
625
                $css[] = $webJsPath."mediaelement/plugins/$feature/$feature.min.css";
626
                $defaultFeatures[] = $feature;
627
            }
628
        }
629
630
        $css[] = $webJsPath.'chosen/chosen.css';
631
632
        if (api_is_global_chat_enabled()) {
633
            $css[] = $webJsPath.'chat/css/chat.css';
634
        }
635
        $css_file_to_string = '';
636
        foreach ($css as $file) {
637
            $css_file_to_string .= api_get_css($file);
638
        }
639
640
        if (!$disable_js_and_css_files) {
641
            $this->assign('css_static_file_to_string', $css_file_to_string);
642
        }
643
644
        $defaultFeatures = implode("','", $defaultFeatures);
645
        $this->assign('video_features', $defaultFeatures);
646
    }
647
648
    /**
649
     * Prepare custom CSS to be added at the very end of the <head> section.
650
     *
651
     * @see setCssFiles() for the mainstream CSS files
652
     */
653
    public function setCssCustomFiles()
654
    {
655
        global $disable_js_and_css_files;
656
        // Base CSS
657
        $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...
658
659
        if ($this->show_learnpath) {
660
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
661
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
662
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
663
            }
664
        }
665
666
        $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
667
        $css[] = api_get_cdn_path(ChamiloApi::getEditorBlockStylePath());
668
669
        $css_file_to_string = null;
670
        foreach ($css as $file) {
671
            $css_file_to_string .= api_get_css($file);
672
        }
673
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
674
        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...
675
            //hack in order to fix the actions buttons
676
            $css_file_to_string .= '<style>
677
                .td_actions a {
678
                    float:left;
679
                    width:100%;
680
                }
681
                .forum_message_left a {
682
                    float:left;
683
                    width:100%;
684
                }
685
                </style>';
686
        }
687
688
        $navigator_info = api_get_navigator();
689
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
690
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
691
        }
692
693
        if (!$disable_js_and_css_files) {
694
            $this->assign('css_custom_file_to_string', $css_file_to_string);
695
696
            $style_print = '';
697
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
698
                $style_print = api_get_css(
699
                    api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->theme.'/print.css'),
700
                    'print'
701
                );
702
            }
703
            $this->assign('css_style_print', $style_print);
704
        }
705
706
        // Logo
707
        $logo = return_logo($this->theme);
708
        $logoPdf = return_logo($this->theme, false);
709
        $this->assign('logo', $logo);
710
        $this->assign('logo_pdf', $logoPdf);
711
        $this->assign('show_media_element', 1);
712
    }
713
714
    /**
715
     * Declare and define the template variable that will be used to load
716
     * javascript libraries in the header.
717
     */
718
    public function set_js_files()
719
    {
720
        global $disable_js_and_css_files, $htmlHeadXtra;
721
        $isoCode = api_get_language_isocode();
722
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
723
724
        if ($isoCode == 'en') {
725
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
726
        }
727
        // JS files
728
        $js_files = [
729
            'chosen/chosen.jquery.min.js',
730
            'mediaelement/plugins/vrview/vrview.js',
731
            'mediaelement/plugins/markersrolls/markersrolls.min.js',
732
        ];
733
734
        if (api_get_setting('accessibility_font_resize') === 'true') {
735
            $js_files[] = 'fontresize.js';
736
        }
737
738
        $js_file_to_string = '';
739
        $bowerJsFiles = [
740
            'modernizr/modernizr.js',
741
            'jquery/dist/jquery.min.js',
742
            'bootstrap/dist/js/bootstrap.min.js',
743
            'jquery-ui/jquery-ui.min.js',
744
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
745
            'moment/min/moment-with-locales.js',
746
            'bootstrap-daterangepicker/daterangepicker.js',
747
            'jquery-timeago/jquery.timeago.js',
748
            'mediaelement/build/mediaelement-and-player.min.js',
749
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
750
            'image-map-resizer/js/imageMapResizer.min.js',
751
            'jquery.scrollbar/jquery.scrollbar.min.js',
752
            'readmore-js/readmore.min.js',
753
            'bootstrap-select/dist/js/bootstrap-select.min.js',
754
            $selectLink,
755
            'select2/dist/js/select2.min.js',
756
            "select2/dist/js/i18n/$isoCode.js",
757
            'js-cookie/src/js.cookie.js',
758
        ];
759
760
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
761
762
        if ($viewBySession || api_is_global_chat_enabled()) {
763
            // Do not include the global chat in LP
764
            if ($this->show_learnpath == false &&
765
                $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...
766
                $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...
767
            ) {
768
                $js_files[] = 'chat/js/chat.js';
769
                $bowerJsFiles[] = 'linkifyjs/linkify.js';
770
                $bowerJsFiles[] = 'linkifyjs/linkify-jquery.js';
771
            }
772
        }
773
774
        $features = api_get_configuration_value('video_features');
775
        if (!empty($features) && isset($features['features'])) {
776
            foreach ($features['features'] as $feature) {
777
                if ($feature === 'vrview') {
778
                    continue;
779
                }
780
                $js_files[] = "mediaelement/plugins/$feature/$feature.min.js";
781
            }
782
        }
783
784
        if (CHAMILO_LOAD_WYSIWYG === true) {
785
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
786
        }
787
788
        if (api_get_setting('include_asciimathml_script') === 'true') {
789
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
790
        }
791
792
        // If not English and the language is supported by timepicker, localize
793
        $assetsPath = api_get_path(SYS_PUBLIC_PATH).'assets/';
794
        if ($isoCode != 'en') {
795
            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')) {
796
                $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
797
                $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
798
            }
799
        }
800
801
        foreach ($bowerJsFiles as $file) {
802
            $js_file_to_string .= '<script type="text/javascript" src="'.api_get_cdn_path(api_get_path(WEB_PUBLIC_PATH).'assets/'.$file).'"></script>'."\n";
803
        }
804
805
        foreach ($js_files as $file) {
806
            $js_file_to_string .= api_get_js($file);
807
        }
808
809
        // Loading email_editor js
810
        if (!api_is_anonymous() && api_get_setting('allow_email_editor') === 'true') {
811
            $template = $this->get_template('mail_editor/email_link.js.tpl');
812
            $js_file_to_string .= $this->fetch($template);
813
        }
814
815
        if (!$disable_js_and_css_files) {
816
            $this->assign('js_file_to_string', $js_file_to_string);
817
818
            $extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
819
            // Adding jquery ui by default
820
            $extraHeaders .= api_get_jquery_ui_js();
821
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
822
                foreach ($htmlHeadXtra as &$this_html_head) {
823
                    $extraHeaders .= $this_html_head."\n";
824
                }
825
            }
826
827
            $ajax = api_get_path(WEB_AJAX_PATH);
828
            $courseId = api_get_course_id();
829
            if (empty($courseId)) {
830
                $courseLogoutCode = '
831
                <script>
832
                function courseLogout() {
833
                }
834
                </script>';
835
            } else {
836
                $courseLogoutCode = "
837
                <script>
838
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
839
                function courseLogout() {
840
                    $.ajax({
841
                        async : false,
842
                        url: logOutUrl,
843
                        success: function (data) {
844
                            return 1;
845
                        }
846
                    });
847
                }
848
                </script>";
849
            }
850
851
            $extraHeaders .= $courseLogoutCode;
852
            $this->assign('extra_headers', $extraHeaders);
853
        }
854
    }
855
856
    /**
857
     * Special function to declare last-minute JS libraries which depend on
858
     * other things to be declared first. In particular, it might be useful
859
     * under IE9 with compatibility mode, which for some reason is getting
860
     * upset when a variable is used in a function (even if not used yet)
861
     * when this variable hasn't been defined yet.
862
     */
863
    public function set_js_files_post()
864
    {
865
        global $disable_js_and_css_files;
866
        $js_files = [];
867
        $bower = '';
868
        if (api_is_global_chat_enabled()) {
869
            //Do not include the global chat in LP
870
            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...
871
                $js_files[] = 'chat/js/chat.js';
872
                $bower .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify.js"></script>';
873
                $bower .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/linkifyjs/linkify-jquery.js"></script>';
874
            }
875
        }
876
        $js_file_to_string = '';
877
        foreach ($js_files as $js_file) {
878
            $js_file_to_string .= api_get_js($js_file);
879
        }
880
        if (!$disable_js_and_css_files) {
881
            $this->assign('js_file_to_string_post', $js_file_to_string.$bower);
882
        }
883
    }
884
885
    /**
886
     * Show header template.
887
     */
888
    public function show_header_template()
889
    {
890
        $tpl = $this->get_template('layout/show_header.tpl');
891
        $this->display($tpl);
892
    }
893
894
    /**
895
     * Show footer template.
896
     */
897
    public function show_footer_template()
898
    {
899
        $tpl = $this->get_template('layout/show_footer.tpl');
900
        $this->display($tpl);
901
    }
902
903
    /**
904
     * Sets the plugin content in a template variable.
905
     *
906
     * @param string $pluginRegion
907
     */
908
    public function set_plugin_region($pluginRegion)
909
    {
910
        if (!empty($pluginRegion)) {
911
            $regionContent = $this->plugin->load_region(
912
                $pluginRegion,
913
                $this,
914
                $this->force_plugin_load
915
            );
916
917
            $pluginList = $this->plugin->getInstalledPlugins(false);
918
            foreach ($pluginList as $plugin_name) {
919
                // The plugin_info variable is available inside the plugin index
920
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
921
922
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
923
                    $courseInfo = api_get_course_info();
924
                    if (!empty($courseInfo)) {
925
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
926
                            /** @var Plugin $plugin */
927
                            $plugin = $pluginInfo['obj'];
928
                            $regionContent .= $plugin->renderRegion($pluginRegion);
929
                        }
930
                    }
931
                } else {
932
                    continue;
933
                }
934
            }
935
936
            if (!empty($regionContent)) {
937
                $this->assign('plugin_'.$pluginRegion, $regionContent);
938
            } else {
939
                $this->assign('plugin_'.$pluginRegion, null);
940
            }
941
        }
942
943
        return null;
944
    }
945
946
    /**
947
     * @param string $template
948
     *
949
     * @return string
950
     */
951
    public function fetch($template = null)
952
    {
953
        $template = $this->twig->loadTemplate($template);
954
955
        return $template->render($this->params);
956
    }
957
958
    /**
959
     * @param string $variable
960
     * @param mixed  $value
961
     */
962
    public function assign($variable, $value = '')
963
    {
964
        $this->params[$variable] = $value;
965
    }
966
967
    /**
968
     * Render the template.
969
     *
970
     * @param string $template           The template path
971
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
972
     */
973
    public function display($template, $clearFlashMessages = true)
974
    {
975
        $this->assign('page_origin', api_get_origin());
976
        $this->assign('flash_messages', Display::getFlashToString());
977
978
        if ($clearFlashMessages) {
979
            Display::cleanFlashMessages();
980
        }
981
982
        echo $this->twig->render($template, $this->params);
983
    }
984
985
    /**
986
     * Adds a body class for login pages.
987
     */
988
    public function setLoginBodyClass()
989
    {
990
        $this->assign('login_class', 'section-login');
991
    }
992
993
    /**
994
     * The theme that will be used if the database is not working.
995
     *
996
     * @return string
997
     */
998
    public static function getThemeFallback()
999
    {
1000
        $theme = api_get_configuration_value('theme_fallback');
1001
        if (empty($theme)) {
1002
            $theme = 'chamilo';
1003
        }
1004
1005
        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...
1006
    }
1007
1008
    /**
1009
     * @param bool|true $setLoginForm
1010
     */
1011
    public function setLoginForm($setLoginForm = true)
1012
    {
1013
        global $loginFailed;
1014
        $userId = api_get_user_id();
1015
        if (!($userId) || api_is_anonymous($userId)) {
1016
            // Only display if the user isn't logged in.
1017
            $this->assign(
1018
                'login_language_form',
1019
                api_display_language_form(true, true)
1020
            );
1021
            if ($setLoginForm) {
1022
                $this->assign('login_form', $this->displayLoginForm());
1023
1024
                if ($loginFailed) {
1025
                    $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

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

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

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