Completed
Push — preprodparkur ( 8b68ba...f1fa91 )
by
unknown
09:06 queued 08:26
created

Template::isToolBarDisplayedForUser()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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

1045
                    $this->assign('login_failed', $this::/** @scrutinizer ignore-call */ handleLoginFailed());
Loading history...
1046
                }
1047
            }
1048
        }
1049
    }
1050
1051
    /**
1052
     * @return string
1053
     */
1054
    public function handleLoginFailed()
1055
    {
1056
        $message = get_lang('InvalidId');
1057
1058
        if (!isset($_GET['error'])) {
1059
            if (api_is_self_registration_allowed()) {
1060
                $message = get_lang('InvalidForSelfRegistration');
1061
            }
1062
        } else {
1063
            switch ($_GET['error']) {
1064
                case '':
1065
                    if (api_is_self_registration_allowed()) {
1066
                        $message = get_lang('InvalidForSelfRegistration');
1067
                    }
1068
                    break;
1069
                case 'account_expired':
1070
                    $message = get_lang('AccountExpired');
1071
                    break;
1072
                case 'account_inactive':
1073
                    $message = get_lang('AccountInactive');
1074
1075
                    if (api_get_setting('allow_registration') === 'confirmation') {
1076
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1077
                        $message .= Display::url(
1078
                            get_lang('ReSendConfirmationMail'),
1079
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1080
                            ['class' => 'alert-link']
1081
                        );
1082
                    }
1083
                    break;
1084
                case 'user_password_incorrect':
1085
                    $message = get_lang('InvalidId');
1086
                    break;
1087
                case 'access_url_inactive':
1088
                    $message = get_lang('AccountURLInactive');
1089
                    break;
1090
                case 'wrong_captcha':
1091
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1092
                    break;
1093
                case 'blocked_by_captcha':
1094
                    $message = get_lang('AccountBlockedByCaptcha');
1095
                    break;
1096
                case 'multiple_connection_not_allowed':
1097
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1098
                    break;
1099
                case 'unrecognize_sso_origin':
1100
                    //$message = get_lang('SSOError');
1101
                    break;
1102
            }
1103
        }
1104
1105
        return Display::return_message($message, 'error', false);
1106
    }
1107
1108
    /**
1109
     * @return string
1110
     */
1111
    public function displayLoginForm()
1112
    {
1113
        $form = new FormValidator(
1114
            'form-login',
1115
            'POST',
1116
            null,
1117
            null,
1118
            null,
1119
            FormValidator::LAYOUT_BOX_NO_LABEL
1120
        );
1121
        $params = [
1122
            'id' => 'login',
1123
            'autofocus' => 'autofocus',
1124
            'icon' => 'user fa-fw',
1125
            'placeholder' => get_lang('UserName'),
1126
        ];
1127
        $browserAutoCapitalize = false;
1128
        // Avoid showing the autocapitalize option if the browser doesn't
1129
        // support it: this attribute is against the HTML5 standard
1130
        if (api_browser_support('autocapitalize')) {
1131
            $browserAutoCapitalize = false;
1132
            $params['autocapitalize'] = 'none';
1133
        }
1134
        $form->addText(
1135
            'login',
1136
            get_lang('UserName'),
1137
            true,
1138
            $params
1139
        );
1140
        $params = [
1141
            'id' => 'password',
1142
            'icon' => 'lock fa-fw',
1143
            'placeholder' => get_lang('Pass'),
1144
        ];
1145
        if ($browserAutoCapitalize) {
1146
            $params['autocapitalize'] = 'none';
1147
        }
1148
        $form->addElement(
1149
            'password',
1150
            'password',
1151
            get_lang('Pass'),
1152
            $params
1153
        );
1154
        // Captcha
1155
        $captcha = api_get_setting('allow_captcha');
1156
        $allowCaptcha = $captcha === 'true';
1157
1158
        if ($allowCaptcha) {
1159
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1160
            if ($useCaptcha) {
1161
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1162
                $options = [
1163
                    'width' => 250,
1164
                    'height' => 90,
1165
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1166
                    'sessionVar' => basename(__FILE__, '.php'),
1167
                    'imageOptions' => [
1168
                        'font_size' => 20,
1169
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1170
                        'font_file' => 'OpenSans-Regular.ttf',
1171
                        //'output' => 'gif'
1172
                    ],
1173
                ];
1174
1175
                // Minimum options using all defaults (including defaults for Image_Text):
1176
                //$options = array('callback' => 'qfcaptcha_image.php');
1177
                $captchaQuestion = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1178
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1179
1180
                $form->addElement(
1181
                    'text',
1182
                    'captcha',
1183
                    get_lang('EnterTheLettersYouSee')
1184
                );
1185
                $form->addRule(
1186
                    'captcha',
1187
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1188
                    'required',
1189
                    null,
1190
                    'client'
1191
                );
1192
                $form->addRule(
1193
                    'captcha',
1194
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1195
                    'CAPTCHA',
1196
                    $captchaQuestion
1197
                );
1198
            }
1199
        }
1200
1201
        $form->addButton(
1202
            'submitAuth',
1203
            get_lang('LoginEnter'),
1204
            null,
1205
            'primary',
1206
            null,
1207
            'btn-block'
1208
        );
1209
1210
        $html = $form->returnForm();
1211
        if (api_get_setting('openid_authentication') == 'true') {
1212
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1213
            $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

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

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