Passed
Push — master ( fbbf1d...35a651 )
by Julito
10:49
created

Template::setAdministratorParams()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
5
use Chamilo\CoreBundle\Framework\Container;
6
use Chamilo\UserBundle\Entity\User;
7
use Symfony\Component\HttpFoundation\Response;
8
9
/**
10
 * Class Template.
11
 *
12
 * @author Julio Montoya <[email protected]>
13
 *
14
 * @todo better organization of the class, methods and variables
15
 */
16
class Template
17
{
18
    /**
19
     * The Template folder name see main/template.
20
     *
21
     * @var string
22
     */
23
    public $templateFolder = 'default';
24
25
    /**
26
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
27
     * This variable is set from the database.
28
     *
29
     * @var string
30
     */
31
    public $theme = '';
32
33
    /**
34
     * @var string
35
     */
36
    public $preview_theme = '';
37
    public $title = null;
38
    public $show_header;
39
    public $show_footer;
40
    public $help;
41
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
42
    public $show_learnpath = false; // This is a learnpath section or not?
43
    public $plugin = null;
44
    public $course_id = null;
45
    public $user_is_logged_in = false;
46
    public $twig = null;
47
48
    /* Loads chamilo plugins */
49
    public $load_plugins = false;
50
    public $params = [];
51
    public $force_plugin_load = false;
52
    public $responseCode = 0;
53
    private $themeDir;
54
55
    /**
56
     * @param string $title
57
     * @param bool   $show_header
58
     * @param bool   $show_footer
59
     * @param bool   $show_learnpath
60
     * @param bool   $hide_global_chat
61
     * @param bool   $load_plugins
62
     * @param int    $responseCode
63
     * @param bool   $sendHeaders      send http headers or not
64
     */
65
    public function __construct(
66
        $title = '',
67
        $show_header = true,
68
        $show_footer = true,
69
        $show_learnpath = false,
70
        $hide_global_chat = false,
71
        $load_plugins = true,
72
        $sendHeaders = true,
73
        $responseCode = 0
74
    ) {
75
        // Page title
76
        $this->title = $title;
77
        $this->show_learnpath = $show_learnpath;
78
        $this->setResponseCode($responseCode);
79
80
        if (empty($this->show_learnpath)) {
81
            $origin = api_get_origin();
82
            if ($origin === 'learnpath') {
83
                $this->show_learnpath = true;
84
                $show_footer = false;
85
                $show_header = false;
86
            }
87
        }
88
        $this->hide_global_chat = $hide_global_chat;
0 ignored issues
show
Bug Best Practice introduced by
The property hide_global_chat does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
89
        $this->load_plugins = $load_plugins;
90
91
        $template_paths = [
92
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
93
            api_get_path(SYS_CODE_PATH).'template', //template folder
94
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
95
            api_get_path(SYS_PATH).'src/ThemeBundle/Resources/views',
96
        ];
97
98
        $urlId = api_get_current_access_url_id();
99
100
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
101
102
        if (!is_dir($cache_folder)) {
103
            //mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
104
        }
105
106
        $loader = new Twig_Loader_Filesystem($template_paths);
107
108
        $isTestMode = api_get_setting('server_type') === 'test';
109
110
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
111
        if ($isTestMode) {
112
            $options = [
113
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
114
                'autoescape' => false,
115
                'debug' => true,
116
                'auto_reload' => true,
117
                'optimizations' => 0,
118
                // turn on optimizations with -1
119
                'strict_variables' => false,
120
                //If set to false, Twig will silently ignore invalid variables
121
            ];
122
        } else {
123
            $options = [
124
                'cache' => $cache_folder,
125
                //path to the cache folder
126
                'autoescape' => false,
127
                'debug' => false,
128
                'auto_reload' => false,
129
                'optimizations' => -1,
130
                // turn on optimizations with -1
131
                'strict_variables' => false,
132
                //If set to false, Twig will silently ignore invalid variables
133
            ];
134
        }
135
136
        //$this->twig = new Twig_Environment($loader, $options);
137
        $this->twig = Container::getTwig();
138
139
        if ($isTestMode) {
140
            //$this->twig->addExtension(new Twig_Extension_Debug());
141
        }
142
143
        // Twig filters setup
144
        $filters = [
145
            'get_plugin_lang',
146
            'get_lang',
147
            'api_get_path',
148
            'api_get_local_time',
149
            'api_convert_and_format_date',
150
            'api_is_allowed_to_edit',
151
            'api_get_user_info',
152
            'api_get_configuration_value',
153
            'api_get_setting',
154
            [
155
                'name' => 'return_message',
156
                'callable' => 'Display::return_message_and_translate',
157
            ],
158
            [
159
                'name' => 'display_page_header',
160
                'callable' => 'Display::page_header_and_translate',
161
            ],
162
            [
163
                'name' => 'display_page_subheader',
164
                'callable' => 'Display::page_subheader_and_translate',
165
            ],
166
            [
167
                'name' => 'icon',
168
                'callable' => 'Template::get_icon_path',
169
            ],
170
            [
171
                'name' => 'img',
172
                'callable' => 'Template::get_image',
173
            ],
174
            [
175
                'name' => 'format_date',
176
                'callable' => 'Template::format_date',
177
            ],
178
            [
179
                'name' => 'get_template',
180
                'callable' => 'Template::findTemplateFilePath',
181
            ],
182
            [
183
                'name' => 'date_to_time_ago',
184
                'callable' => 'Display::dateToStringAgoAndLongDate',
185
            ],
186
        ];
187
188
        foreach ($filters as $filter) {
189
            if (is_array($filter)) {
190
                //$this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
191
            } else {
192
                //$this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
193
            }
194
        }
195
196
        /*$this->twig->addFunction(
197
            new TwigFunction('sonata_page_render_container', [$this, 'renderContainer'], ['is_safe' => ['html']])
198
        );*/
199
200
        $functions = [
201
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
202
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
203
        ];
204
205
        foreach ($functions as $function) {
206
            //$this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
207
        }
208
209
        // Setting system variables
210
        $this->set_system_parameters();
211
212
        // Setting user variables
213
        $this->set_user_parameters();
214
215
        // Setting course variables
216
        $this->set_course_parameters();
217
218
        // Setting administrator variables
219
        //$this->setAdministratorParams();
220
        //$this->setCSSEditor();
221
222
        // Header and footer are showed by default
223
        $this->set_footer($show_footer);
224
        $this->set_header($show_header);
225
226
        $this->set_header_parameters($sendHeaders);
227
        $this->set_footer_parameters();
228
229
        $defaultStyle = api_get_configuration_value('default_template');
230
        if (!empty($defaultStyle)) {
231
            $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...
232
        }
233
234
        $this->assign('template', $this->templateFolder);
235
        $this->assign('locale', api_get_language_isocode());
236
        $this->assign('login_class', null);
237
238
        // Chamilo plugins
239
        if ($this->show_header) {
240
            if ($this->load_plugins) {
241
                $this->plugin = new AppPlugin();
242
243
                //1. Showing installed plugins in regions
244
                $pluginRegions = $this->plugin->get_plugin_regions();
245
                foreach ($pluginRegions as $region) {
246
                    $this->set_plugin_region($region);
247
                }
248
249
                //2. Loading the course plugin info
250
                global $course_plugin;
251
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
252
                    //Load plugin get_langs
253
                    $this->plugin->load_plugin_lang_variables($course_plugin);
254
                }
255
            }
256
        }
257
    }
258
259
    /**
260
     * @param string $image
261
     * @param int    $size
262
     *
263
     * @return string
264
     */
265
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
266
    {
267
        return Display::return_icon($image, '', [], $size, false, true);
268
    }
269
270
    /**
271
     * @param string $image
272
     * @param int    $size
273
     * @param string $name
274
     *
275
     * @return string
276
     */
277
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
278
    {
279
        return Display::return_icon($image, $name, [], $size);
280
    }
281
282
    /**
283
     * @param string $timestamp
284
     * @param string $format
285
     *
286
     * @return string
287
     */
288
    public static function format_date($timestamp, $format = null)
289
    {
290
        return api_format_date($timestamp, $format);
291
    }
292
293
    /**
294
     * Return the item's url key:.
295
     *
296
     *      c_id=xx&id=xx
297
     *
298
     * @param object $item
299
     *
300
     * @return string
301
     */
302
    public static function key($item)
303
    {
304
        $id = isset($item->id) ? $item->id : null;
305
        $c_id = isset($item->c_id) ? $item->c_id : null;
306
        $result = '';
307
        if ($c_id) {
308
            $result = "c_id=$c_id";
309
        }
310
        if ($id) {
311
            if ($result) {
312
                $result .= "&amp;id=$id";
313
            } else {
314
                $result .= "&amp;id=$id";
315
            }
316
        }
317
318
        return $result;
319
    }
320
321
    /**
322
     * @param string $helpInput
323
     */
324
    public function setHelp($helpInput = null)
325
    {
326
        if (!empty($helpInput)) {
327
            $help = $helpInput;
328
        } else {
329
            $help = $this->help;
330
        }
331
332
        $content = '';
333
        if (api_get_setting('enable_help_link') == 'true') {
334
            if (!empty($help)) {
335
                $help = Security::remove_XSS($help);
336
                $content = '<div class="help">';
337
                $content .= Display::url(
338
                    Display::return_icon('help.large.png', get_lang('Help')),
339
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
340
                    [
341
                        'class' => 'ajax',
342
                        'data-title' => get_lang('Help'),
343
                    ]
344
                );
345
                $content .= '</div>';
346
            }
347
        }
348
        $this->assign('help_content', $content);
349
    }
350
351
    /**
352
     * Use template system to parse the actions menu.
353
     *
354
     * @todo finish it!
355
     */
356
    public function set_actions($actions)
357
    {
358
        $action_string = '';
359
        if (!empty($actions)) {
360
            foreach ($actions as $action) {
361
                $action_string .= $action;
362
            }
363
        }
364
        $this->assign('actions', $actions);
365
    }
366
367
    /**
368
     * Render the template.
369
     *
370
     * @param string $template           The template path
371
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
372
     */
373
    public function display($template, $clearFlashMessages = true)
0 ignored issues
show
Unused Code introduced by
The parameter $clearFlashMessages is not used and could be removed. ( Ignorable by Annotation )

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

373
    public function display($template, /** @scrutinizer ignore-unused */ $clearFlashMessages = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
374
    {
375
        $template = str_replace('tpl', 'html.twig', $template);
376
        $templateFile = api_get_path(SYS_PATH).'main/template/'.$template;
377
378
        // Set legacy breadcrumb
379
        global $interbreadcrumb;
380
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
381
382
        if (!file_exists($templateFile)) {
383
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
384
            echo $e->getMessage();
385
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
386
        }
387
388
        $this->returnResponse($this->params, $template);
389
    }
390
391
    /**
392
     * @param array  $params
393
     * @param string $template
394
     *
395
     * @throws \Twig\Error\Error
396
     */
397
    public function returnResponse($params, $template)
398
    {
399
        $flash = Display::getFlashToString();
400
        Display::cleanFlashMessages();
401
        $response = new Response();
402
        $params['flash_messages'] = $flash;
403
        $content = Container::getTemplating()->render($template, $params);
404
        $response->setContent($content);
405
        $response->send();
406
    }
407
408
    /**
409
     * Shortcut to display a 1 col layout (index.php).
410
     * */
411
    public function display_one_col_template()
412
    {
413
        $template = '@ChamiloTheme/Layout/layout_one_col.html.twig';
414
        $this->returnResponse($this->params, $template);
415
    }
416
417
    /**
418
     * Shortcut to display a 2 col layout (userportal.php).
419
     */
420
    public function display_two_col_template()
421
    {
422
        $template = '@ChamiloTheme/Layout/layout_two_col.html.twig';
423
        $this->returnResponse($this->params, $template);
424
    }
425
426
    /**
427
     * Displays an empty template.
428
     */
429
    public function display_blank_template()
430
    {
431
        $template = '@ChamiloTheme/Layout/blank.html.twig';
432
        $this->returnResponse($this->params, $template);
433
    }
434
435
    /**
436
     * Displays an empty template.
437
     */
438
    public function displayBlankTemplateNoHeader()
439
    {
440
        $template = '@ChamiloTheme/Layout/blank_no_header.html.twig';
441
        $this->returnResponse($this->params, $template);
442
    }
443
444
    /**
445
     * Displays an empty template.
446
     */
447
    public function display_no_layout_template()
448
    {
449
        $template = '@ChamiloTheme/Layout/no_layout.html.twig';
450
        $this->returnResponse($this->params, $template);
451
    }
452
453
    /**
454
     * Displays an empty template.
455
     */
456
    public function displaySkillLayout()
457
    {
458
        $template = '@ChamiloTheme/Layout/skill_layout.html.twig';
459
        $this->returnResponse($this->params, $template);
460
    }
461
462
    /**
463
     * Sets the footer visibility.
464
     *
465
     * @param bool true if we show the footer
466
     */
467
    public function set_footer($status)
468
    {
469
        $this->show_footer = $status;
470
        $this->assign('show_footer', $status);
471
    }
472
473
    /**
474
     * return true if toolbar has to be displayed for user.
475
     *
476
     * @return bool
477
     */
478
    public static function isToolBarDisplayedForUser()
479
    {
480
        //Toolbar
481
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
482
        $show_toolbar = false;
483
484
        switch ($show_admin_toolbar) {
485
            case 'do_not_show':
486
                break;
487
            case 'show_to_admin':
488
                if (api_is_platform_admin()) {
489
                    $show_toolbar = true;
490
                }
491
                break;
492
            case 'show_to_admin_and_teachers':
493
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
494
                    $show_toolbar = true;
495
                }
496
                break;
497
            case 'show_to_all':
498
                $show_toolbar = true;
499
                break;
500
        }
501
502
        return $show_toolbar;
503
    }
504
505
    /**
506
     * Sets the header visibility.
507
     *
508
     * @param bool true if we show the header
509
     */
510
    public function set_header($status)
511
    {
512
        $this->show_header = $status;
513
        $this->assign('show_header', $status);
514
515
        $show_toolbar = 0;
516
        if (self::isToolBarDisplayedForUser()) {
517
            $show_toolbar = 1;
518
        }
519
520
        $this->assign('show_toolbar', $show_toolbar);
521
522
        //Only if course is available
523
        $show_course_shortcut = null;
524
        $show_course_navigation_menu = null;
525
526
        if (!empty($this->course_id) && $this->user_is_logged_in) {
527
            if (api_get_setting('show_toolshortcuts') !== 'false') {
528
                //Course toolbar
529
                $show_course_shortcut = CourseHome::getCourseToolBar();
530
            }
531
            if (api_get_setting('show_navigation_menu') !== 'false') {
532
                //Course toolbar
533
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
534
            }
535
        }
536
        $this->assign('show_course_shortcut', $show_course_shortcut);
537
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
538
    }
539
540
    /**
541
     * Returns the sub-folder and filename for the given tpl file.
542
     * If template not found in overrides/ or custom template folder, the
543
     * default template will be used.
544
     *
545
     * @param string $name
546
     *
547
     * @return string
548
     */
549
    public function get_template($name)
550
    {
551
        // Check if the tpl file is present in the main/template/overrides/ dir
552
        // Overrides is a special directory meant for temporary template
553
        // customization. It must be taken into account before anything else
554
        $file = api_get_path(SYS_CODE_PATH).'template/overrides/'.$name;
555
        if (is_readable($file)) {
556
            return 'overrides/'.$name;
557
        }
558
        // If a template folder has been manually defined, search for the right
559
        // file, and if not found, go for the same file in the default template
560
        if ($this->templateFolder != 'default') {
561
            // Avoid missing template error, use the default file.
562
            $file = api_get_path(SYS_CODE_PATH).'template/'.$this->templateFolder.'/'.$name;
563
            if (!file_exists($file)) {
564
                return 'default/'.$name;
565
            }
566
        }
567
        $name = str_replace('tpl', 'html.twig', $name);
568
569
        return $this->templateFolder.'/'.$name;
570
    }
571
572
    /**
573
     * Get CSS themes sub-directory.
574
     *
575
     * @param string $theme
576
     *
577
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
578
     */
579
    public static function getThemeDir($theme)
580
    {
581
        $themeDir = 'themes/'.$theme.'/';
582
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
583
        if (!empty($virtualTheme)) {
584
            $virtualThemeList = api_get_themes(true);
585
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
586
            if ($isVirtualTheme) {
587
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
588
            }
589
        }
590
591
        return $themeDir;
592
    }
593
594
    /**
595
     * Set system parameters from api_get_configuration into _s array for use in TPLs
596
     * Also fills the _p array from getWebPaths().
597
     *
598
     * @uses \self::getWebPaths()
599
     */
600
    public function set_system_parameters()
601
    {
602
        $this->theme = api_get_visual_theme();
603
        if (!empty($this->preview_theme)) {
604
            $this->theme = $this->preview_theme;
605
        }
606
607
        $this->assign('theme', $this->theme);
608
609
        $this->themeDir = self::getThemeDir($this->theme);
610
611
        // Setting app paths/URLs
612
        //$this->assign('_p', $this->getWebPaths());
613
614
        // Here we can add system parameters that can be use in any template
615
        $_s = [
616
            'software_name' => api_get_configuration_value('software_name'),
617
            'system_version' => api_get_configuration_value('system_version'),
618
            'site_name' => api_get_setting('siteName'),
619
            'institution' => api_get_setting('Institution'),
620
            'date' => api_format_date('now', DATE_FORMAT_LONG),
621
            'timezone' => api_get_timezone(),
622
            'gamification_mode' => api_get_setting('gamification_mode'),
623
        ];
624
        $this->assign('_s', $_s);
625
    }
626
627
    /**
628
     * Set legacy twig globals in order to be hook in the LegacyListener.php.
629
     *
630
     * @return array
631
     */
632
    public static function getGlobals()
633
    {
634
        $queryString = empty($_SERVER['QUERY_STRING']) ? '' : $_SERVER['QUERY_STRING'];
635
        $requestURI = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
636
637
        $_p = [
638
            'web' => api_get_path(WEB_PATH),
639
            'web_public' => api_get_path(WEB_PUBLIC_PATH),
640
            'web_url' => api_get_web_url(),
641
            'web_relative' => api_get_path(REL_PATH),
642
            'web_course' => api_get_path(WEB_COURSE_PATH),
643
            'web_main' => api_get_path(WEB_CODE_PATH),
644
            'web_css' => api_get_path(WEB_CSS_PATH),
645
            //'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
646
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
647
            'web_img' => api_get_path(WEB_IMG_PATH),
648
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
649
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
650
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
651
            'web_self' => api_get_self(),
652
            'web_query_vars' => api_htmlentities($queryString),
653
            'web_self_query_vars' => api_htmlentities($requestURI),
654
            'web_cid_query' => api_get_cidreq(),
655
            'web_rel_code' => api_get_path(REL_CODE_PATH),
656
        ];
657
658
        $_s = [
659
            'software_name' => api_get_configuration_value('software_name'),
660
            'system_version' => api_get_configuration_value('system_version'),
661
            'site_name' => api_get_setting('siteName'),
662
            'institution' => api_get_setting('Institution'),
663
            //'date' => api_format_date('now', DATE_FORMAT_LONG),
664
            'date' => '',
665
            'timezone' => '',
666
            //'timezone' => api_get_timezone(),
667
            'gamification_mode' => api_get_setting('gamification_mode'),
668
        ];
669
670
        //$user_info = api_get_user_info();
671
672
        return [
673
            '_p' => $_p,
674
            '_s' => $_s,
675
            //       '_u' => $user_info,
676
            'template' => 'default', // @todo setup template folder in config.yml;
677
        ];
678
    }
679
680
    /**
681
     * Set theme, include mainstream CSS files.
682
     *
683
     * @deprecated
684
     * @see setCssCustomFiles() for additional CSS sheets
685
     */
686
    public function setCssFiles()
687
    {
688
        global $disable_js_and_css_files;
689
        $css = [];
690
691
        // Default CSS Bootstrap
692
        $bowerCSSFiles = [
693
            'fontawesome/css/font-awesome.min.css',
694
            'jquery-ui/themes/smoothness/theme.css',
695
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
696
            'mediaelement/build/mediaelementplayer.min.css',
697
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
698
            'bootstrap/dist/css/bootstrap.min.css',
699
            'jquery.scrollbar/jquery.scrollbar.css',
700
            //'bootstrap-daterangepicker/daterangepicker.css',
701
            'bootstrap-select/dist/css/bootstrap-select.min.css',
702
            'select2/dist/css/select2.min.css',
703
            'flag-icon-css/css/flag-icon.min.css',
704
            'mediaelement/plugins/vrview/vrview.css',
705
        ];
706
707
        $features = api_get_configuration_value('video_features');
708
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen', 'vrview'];
709
710
        if (!empty($features) && isset($features['features'])) {
711
            foreach ($features['features'] as $feature) {
712
                if ($feature === 'vrview') {
713
                    continue;
714
                }
715
                $bowerCSSFiles[] = "mediaelement/plugins/$feature/$feature.css";
716
                $defaultFeatures[] = $feature;
717
            }
718
        }
719
720
        foreach ($bowerCSSFiles as $file) {
721
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
722
        }
723
724
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
725
726
        if (api_is_global_chat_enabled()) {
727
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
728
        }
729
        $css_file_to_string = '';
730
        foreach ($css as $file) {
731
            $css_file_to_string .= api_get_css($file);
732
        }
733
734
        if (!$disable_js_and_css_files) {
735
            $this->assign('css_static_file_to_string', $css_file_to_string);
736
        }
737
738
        $defaultFeatures = implode("','", $defaultFeatures);
739
        $this->assign('video_features', $defaultFeatures);
740
    }
741
742
    /**
743
     * Sets the "styles" menu in ckEditor.
744
     *
745
     * Reads css/themes/xxx/editor.css if exists and shows it in the menu, otherwise it
746
     * will take the default web/editor.css file
747
     */
748
    public function setStyleMenuInCkEditor()
749
    {
750
        $cssEditor = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'editor.css');
751
        if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'editor.css')) {
752
            $cssEditor = api_get_path(WEB_CSS_PATH).$this->themeDir.'editor.css';
753
        }
754
        $this->assign('css_editor', $cssEditor);
755
    }
756
757
    /**
758
     * Prepare custom CSS to be added at the very end of the <head> section.
759
     *
760
     * @see setCssFiles() for the mainstream CSS files
761
     */
762
    public function setCssCustomFiles()
763
    {
764
        global $disable_js_and_css_files;
765
        // chamilo CSS
766
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'../chamilo.css');
767
768
        // Base CSS
769
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.css');
770
        $css = [];
771
        if ($this->show_learnpath) {
772
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
773
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
774
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
775
            }
776
        }
777
778
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
779
        $css_file_to_string = '';
780
        foreach ($css as $file) {
781
            $css_file_to_string .= api_get_css($file);
782
        }
783
784
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
785
        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...
786
            //hack in order to fix the actions buttons
787
            $css_file_to_string .= '<style>
788
                .td_actions a {
789
                    float:left;
790
                    width:100%;
791
                }
792
                .forum_message_left a {
793
                    float:left;
794
                    width:100%;
795
                }
796
                </style>';
797
        }
798
799
        $navigator_info = api_get_navigator();
800
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
801
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
802
        }
803
804
        if (!$disable_js_and_css_files) {
805
            $this->assign('css_custom_file_to_string', $css_file_to_string);
806
807
            $style_print = '';
808
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
809
                $style_print = api_get_css(
810
                    api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->theme.'/print.css'),
811
                    'print'
812
                );
813
            }
814
            $this->assign('css_style_print', $style_print);
815
        }
816
817
        // Logo
818
        $logo = return_logo($this->theme);
819
        $this->assign('logo', $logo);
820
        $this->assign('show_media_element', 1);
821
    }
822
823
    /**
824
     * Declare and define the template variable that will be used to load
825
     * javascript libraries in the header.
826
     */
827
    public function set_js_files()
828
    {
829
        global $disable_js_and_css_files, $htmlHeadXtra;
830
        $isoCode = api_get_language_isocode();
831
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
832
833
        if ($isoCode == 'en') {
834
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
835
        }
836
        // JS files
837
        $js_files = [
838
            'chosen/chosen.jquery.min.js',
839
        ];
840
841
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
842
843
        if (api_is_global_chat_enabled() || $viewBySession) {
844
            // Do not include the global chat in LP
845
            if ($this->show_learnpath == false &&
846
                $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...
847
                $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...
848
            ) {
849
                $js_files[] = 'chat/js/chat.js';
850
            }
851
        }
852
853
        if (api_get_setting('accessibility_font_resize') === 'true') {
854
            $js_files[] = 'fontresize.js';
855
        }
856
857
        $js_file_to_string = '';
858
        $bowerJsFiles = [
859
            'modernizr/modernizr.js',
860
            'jquery/dist/jquery.min.js',
861
            'bootstrap/dist/js/bootstrap.min.js',
862
            'jquery-ui/jquery-ui.min.js',
863
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
864
            'moment/min/moment-with-locales.js',
865
            //'bootstrap-daterangepicker/daterangepicker.js',
866
            'jquery-timeago/jquery.timeago.js',
867
            'mediaelement/build/mediaelement-and-player.min.js',
868
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
869
            'image-map-resizer/js/imageMapResizer.min.js',
870
            'jquery.scrollbar/jquery.scrollbar.min.js',
871
            //'readmore-js/readmore.min.js',
872
            'bootstrap-select/dist/js/bootstrap-select.min.js',
873
            $selectLink,
874
            'select2/dist/js/select2.min.js',
875
            "select2/dist/js/i18n/$isoCode.js",
876
            'mediaelement/plugins/vrview/vrview.js',
877
        ];
878
879
        $features = api_get_configuration_value('video_features');
880
        if (!empty($features) && isset($features['features'])) {
881
            foreach ($features['features'] as $feature) {
882
                if ($feature === 'vrview') {
883
                    continue;
884
                }
885
                $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js";
886
            }
887
        }
888
889
        if (CHAMILO_LOAD_WYSIWYG === true) {
890
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
891
        }
892
893
        if (api_get_setting('include_asciimathml_script') === 'true') {
894
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
895
        }
896
897
        if ($isoCode != 'en') {
898
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
899
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
900
        }
901
902
        foreach ($bowerJsFiles as $file) {
903
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
904
        }
905
906
        foreach ($js_files as $file) {
907
            //$js_file_to_string .= api_get_js($file);
908
        }
909
910
        // Loading email_editor js
911
        if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') {
912
            $template = $this->get_template('mail_editor/email_link.js.tpl');
913
            $js_file_to_string .= $this->fetch($template);
914
        }
915
916
        if (!$disable_js_and_css_files) {
917
            $this->assign('js_file_to_string', $js_file_to_string);
918
            $extraHeaders = '';
919
            //$extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
920
            //Adding jquery ui by default
921
            $extraHeaders .= api_get_jquery_ui_js();
922
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
923
                foreach ($htmlHeadXtra as &$this_html_head) {
924
                    $extraHeaders .= $this_html_head."\n";
925
                }
926
            }
927
928
            $ajax = api_get_path(WEB_AJAX_PATH);
929
            $courseId = api_get_course_id();
930
            if (empty($courseId)) {
931
                $courseLogoutCode = '
932
                <script>
933
                function courseLogout() {
934
                }
935
                </script>';
936
            } else {
937
                $courseLogoutCode = "
938
                <script>
939
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
940
                function courseLogout() {                
941
                    $.ajax({
942
                        async : false,
943
                        url: logOutUrl,
944
                        success: function (data) {
945
                            return 1;
946
                        }
947
                    });
948
                }
949
                </script>";
950
            }
951
952
            $extraHeaders .= $courseLogoutCode;
953
            $this->assign('extra_headers', $extraHeaders);
954
        }
955
    }
956
957
    /**
958
     * Special function to declare last-minute JS libraries which depend on
959
     * other things to be declared first. In particular, it might be useful
960
     * under IE9 with compatibility mode, which for some reason is getting
961
     * upset when a variable is used in a function (even if not used yet)
962
     * when this variable hasn't been defined yet.
963
     */
964
    public function set_js_files_post()
965
    {
966
        global $disable_js_and_css_files;
967
        $js_files = [];
968
        if (api_is_global_chat_enabled()) {
969
            //Do not include the global chat in LP
970
            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...
971
                $js_files[] = 'chat/js/chat.js';
972
            }
973
        }
974
        $js_file_to_string = '';
975
        foreach ($js_files as $js_file) {
976
            $js_file_to_string .= api_get_js($js_file);
977
        }
978
        if (!$disable_js_and_css_files) {
979
            $this->assign('js_file_to_string_post', $js_file_to_string);
980
        }
981
    }
982
983
    /**
984
     * @param string $theme
985
     *
986
     * @return string
987
     */
988
    public static function getPortalIcon($theme)
989
    {
990
        // Default root chamilo favicon
991
        $icon = '<link rel="shortcut icon" href="'.api_get_path(WEB_PUBLIC_PATH).'favicon.ico" type="image/x-icon" />';
992
993
        // Added to verify if in the current Chamilo Theme exist a favicon
994
        $themeUrl = api_get_path(SYS_CSS_PATH).'themes/'.$theme.'/images/';
995
996
        //If exist pick the current chamilo theme favicon
997
        if (is_file($themeUrl.'favicon.ico')) {
998
            $icon = '<link rel="shortcut icon" href="'.api_get_path(WEB_PUBLIC_PATH).'build/css/themes/'.$theme.'/images/favicon.ico" type="image/x-icon" />';
999
        }
1000
1001
        return $icon;
1002
    }
1003
1004
    /**
1005
     * Show header template.
1006
     */
1007
    public function show_header_template()
1008
    {
1009
        $tpl = $this->get_template('layout/show_header.tpl');
1010
        $this->display($tpl);
1011
    }
1012
1013
    /**
1014
     * Show footer template.
1015
     */
1016
    public function show_footer_template()
1017
    {
1018
        $tpl = $this->get_template('layout/show_footer.tpl');
1019
        $this->display($tpl);
1020
    }
1021
1022
    /**
1023
     * Show footer js template.
1024
     */
1025
    public function show_footer_js_template()
1026
    {
1027
        $tpl = $this->get_template('layout/footer.js.tpl');
1028
        $this->display($tpl);
1029
    }
1030
1031
    /**
1032
     * Sets the plugin content in a template variable.
1033
     *
1034
     * @param string $pluginRegion
1035
     */
1036
    public function set_plugin_region($pluginRegion)
1037
    {
1038
        if (!empty($pluginRegion)) {
1039
            $regionContent = $this->plugin->load_region(
1040
                $pluginRegion,
1041
                $this,
1042
                $this->force_plugin_load
1043
            );
1044
1045
            $pluginList = $this->plugin->get_installed_plugins();
1046
            foreach ($pluginList as $plugin_name) {
1047
                // The plugin_info variable is available inside the plugin index
1048
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
1049
1050
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
1051
                    $courseInfo = api_get_course_info();
1052
                    if (!empty($courseInfo)) {
1053
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
1054
                            /** @var Plugin $plugin */
1055
                            $plugin = $pluginInfo['obj'];
1056
                            $regionContent .= $plugin->renderRegion($pluginRegion);
1057
                        }
1058
                    }
1059
                } else {
1060
                    continue;
1061
                }
1062
            }
1063
1064
            if (!empty($regionContent)) {
1065
                $this->assign('plugin_'.$pluginRegion, $regionContent);
1066
            } else {
1067
                $this->assign('plugin_'.$pluginRegion, null);
1068
            }
1069
        }
1070
1071
        return null;
1072
    }
1073
1074
    /**
1075
     * @param string $template
1076
     *
1077
     * @return string
1078
     */
1079
    public function fetch($template = null)
1080
    {
1081
        $template = $this->twig->loadTemplate($template);
1082
1083
        return $template->render($this->params);
1084
    }
1085
1086
    /**
1087
     * @param string $variable
1088
     * @param mixed  $value
1089
     */
1090
    public function assign($variable, $value = '')
1091
    {
1092
        $this->params[$variable] = $value;
1093
    }
1094
1095
    /**
1096
     * Adds a body class for login pages.
1097
     */
1098
    public function setLoginBodyClass()
1099
    {
1100
        $this->assign('login_class', 'section-login');
1101
    }
1102
1103
    /**
1104
     * The theme that will be used if the database is not working.
1105
     *
1106
     * @return string
1107
     */
1108
    public static function getThemeFallback()
1109
    {
1110
        $theme = api_get_configuration_value('theme_fallback');
1111
        if (empty($theme)) {
1112
            $theme = 'chamilo';
1113
        }
1114
1115
        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...
1116
    }
1117
1118
    /**
1119
     * @return string
1120
     */
1121
    public function handleLoginFailed()
1122
    {
1123
        $message = get_lang('InvalidId');
1124
1125
        if (!isset($_GET['error'])) {
1126
            if (api_is_self_registration_allowed()) {
1127
                $message = get_lang('InvalidForSelfRegistration');
1128
            }
1129
        } else {
1130
            switch ($_GET['error']) {
1131
                case '':
1132
                    if (api_is_self_registration_allowed()) {
1133
                        $message = get_lang('InvalidForSelfRegistration');
1134
                    }
1135
                    break;
1136
                case 'account_expired':
1137
                    $message = get_lang('AccountExpired');
1138
                    break;
1139
                case 'account_inactive':
1140
                    $message = get_lang('AccountInactive');
1141
1142
                    if (api_get_setting('allow_registration') === 'confirmation') {
1143
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1144
                        $message .= Display::url(
1145
                            get_lang('ReSendConfirmationMail'),
1146
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1147
                            ['class' => 'alert-link']
1148
                        );
1149
                    }
1150
                    break;
1151
                case 'user_password_incorrect':
1152
                    $message = get_lang('InvalidId');
1153
                    break;
1154
                case 'access_url_inactive':
1155
                    $message = get_lang('AccountURLInactive');
1156
                    break;
1157
                case 'wrong_captcha':
1158
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1159
                    break;
1160
                case 'blocked_by_captcha':
1161
                    $message = get_lang('AccountBlockedByCaptcha');
1162
                    break;
1163
                case 'multiple_connection_not_allowed':
1164
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1165
                    break;
1166
                case 'unrecognize_sso_origin':
1167
                    //$message = get_lang('SSOError');
1168
                    break;
1169
            }
1170
        }
1171
1172
        return Display::return_message($message, 'error', false);
1173
    }
1174
1175
    /**
1176
     * @return string
1177
     */
1178
    public function displayLoginForm()
1179
    {
1180
        $form = new FormValidator(
1181
            'form-login',
1182
            'POST',
1183
            api_get_path(WEB_PUBLIC_PATH).'login_check',
1184
            null,
1185
            null,
1186
            FormValidator::LAYOUT_BOX_NO_LABEL
1187
        );
1188
        $params = [
1189
            'id' => '_username',
1190
            'autofocus' => 'autofocus',
1191
            'icon' => 'user fa-fw',
1192
            'placeholder' => get_lang('UserName'),
1193
        ];
1194
        $browserAutoCapitalize = false;
1195
        // Avoid showing the autocapitalize option if the browser doesn't
1196
        // support it: this attribute is against the HTML5 standard
1197
        if (api_browser_support('autocapitalize')) {
1198
            $browserAutoCapitalize = false;
1199
            $params['autocapitalize'] = 'none';
1200
        }
1201
        $form->addText(
1202
            '_username',
1203
            get_lang('UserName'),
1204
            true,
1205
            $params
1206
        );
1207
        $params = [
1208
            'id' => '_password',
1209
            'icon' => 'lock fa-fw',
1210
            'placeholder' => get_lang('Pass'),
1211
        ];
1212
        if ($browserAutoCapitalize) {
1213
            $params['autocapitalize'] = 'none';
1214
        }
1215
        $form->addElement(
1216
            'password',
1217
            '_password',
1218
            get_lang('Pass'),
1219
            $params
1220
        );
1221
1222
        $token = Chamilo\CoreBundle\Framework\Container::$container->get('security.csrf.token_manager')->getToken('authenticate');
1223
        $form->addHidden('_csrf_token', $token->getValue());
1224
1225
        // Captcha
1226
        $captcha = api_get_setting('allow_captcha');
1227
        $allowCaptcha = $captcha === 'true';
1228
1229
        if ($allowCaptcha) {
1230
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1231
            if ($useCaptcha) {
1232
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1233
                $options = [
1234
                    'width' => 250,
1235
                    'height' => 90,
1236
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1237
                    'sessionVar' => basename(__FILE__, '.php'),
1238
                    'imageOptions' => [
1239
                        'font_size' => 20,
1240
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1241
                        'font_file' => 'OpenSans-Regular.ttf',
1242
                        //'output' => 'gif'
1243
                    ],
1244
                ];
1245
1246
                // Minimum options using all defaults (including defaults for Image_Text):
1247
                //$options = array('callback' => 'qfcaptcha_image.php');
1248
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1249
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1250
1251
                $form->addElement(
1252
                    'text',
1253
                    'captcha',
1254
                    get_lang('EnterTheLettersYouSee')
1255
                );
1256
                $form->addRule(
1257
                    'captcha',
1258
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1259
                    'required',
1260
                    null,
1261
                    'client'
1262
                );
1263
                $form->addRule(
1264
                    'captcha',
1265
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1266
                    'CAPTCHA',
1267
                    $captcha_question
1268
                );
1269
            }
1270
        }
1271
1272
        $form->addButton(
1273
            'submitAuth',
1274
            get_lang('LoginEnter'),
1275
            null,
1276
            'primary',
1277
            null,
1278
            'btn-block'
1279
        );
1280
1281
        $html = $form->returnForm();
1282
1283
        return $html;
1284
    }
1285
1286
    /**
1287
     * Returns the tutors names for the current course in session
1288
     * Function to use in Twig templates.
1289
     *
1290
     * @return string
1291
     */
1292
    public static function returnTutorsNames()
1293
    {
1294
        $em = Database::getManager();
1295
        $tutors = $em
1296
            ->createQuery('
1297
                SELECT u FROM ChamiloUserBundle:User u
1298
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1299
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1300
            ')
1301
            ->setParameters([
1302
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1303
                'session' => api_get_session_id(),
1304
                'course' => api_get_course_int_id(),
1305
            ])
1306
            ->getResult();
1307
1308
        $names = [];
1309
1310
        /** @var User $tutor */
1311
        foreach ($tutors as $tutor) {
1312
            $names[] = $tutor->getCompleteName();
1313
        }
1314
1315
        return implode(CourseManager::USER_SEPARATOR, $names);
1316
    }
1317
1318
    /*s
1319
     * Returns the teachers name for the current course
1320
     * Function to use in Twig templates
1321
     * @return string
1322
     */
1323
    public static function returnTeachersNames()
1324
    {
1325
        $em = Database::getManager();
1326
        $teachers = $em
1327
            ->createQuery('
1328
                SELECT u FROM ChamiloUserBundle:User u
1329
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1330
                WHERE cu.status = :teacher_status AND cu.course = :course
1331
            ')
1332
            ->setParameters([
1333
                'teacher_status' => User::COURSE_MANAGER,
1334
                'course' => api_get_course_int_id(),
1335
            ])
1336
            ->getResult();
1337
1338
        $names = [];
1339
1340
        /** @var User $teacher */
1341
        foreach ($teachers as $teacher) {
1342
            $names[] = $teacher->getCompleteName();
1343
        }
1344
1345
        return implode(CourseManager::USER_SEPARATOR, $names);
1346
    }
1347
1348
    /**
1349
     * @param int $code
1350
     */
1351
    public function setResponseCode($code)
1352
    {
1353
        $this->responseCode = $code;
1354
    }
1355
1356
    /**
1357
     * @param string $code
1358
     */
1359
    public function getResponseCode()
1360
    {
1361
        return $this->responseCode;
1362
    }
1363
1364
    /**
1365
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1366
     *
1367
     * @return bool Always return true because there is always a string, even if empty
1368
     */
1369
    public function assignBugNotification()
1370
    {
1371
        //@todo move this in the template
1372
        $rightFloatMenu = '';
1373
        $iconBug = Display::return_icon(
1374
            'bug.png',
1375
            get_lang('ReportABug'),
1376
            [],
1377
            ICON_SIZE_LARGE
1378
        );
1379
        if (api_get_setting('show_link_bug_notification') === 'true' && $this->user_is_logged_in) {
1380
            $rightFloatMenu = '<div class="report">
1381
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1382
                    '.$iconBug.'
1383
                </a>
1384
		        </div>';
1385
        }
1386
1387
        if (api_get_setting('show_link_ticket_notification') === 'true' &&
1388
            $this->user_is_logged_in
1389
        ) {
1390
            // by default is project_id = 1
1391
            $defaultProjectId = 1;
1392
            $iconTicket = Display::return_icon(
1393
                'help.png',
1394
                get_lang('Ticket'),
1395
                [],
1396
                ICON_SIZE_LARGE
1397
            );
1398
            $courseInfo = api_get_course_info();
1399
            $courseParams = '';
1400
            if (!empty($courseInfo)) {
1401
                $courseParams = api_get_cidreq();
1402
            }
1403
            $url = api_get_path(WEB_CODE_PATH).
1404
                'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams;
1405
            $rightFloatMenu .= '<div class="help">
1406
                <a href="'.$url.'" target="_blank">
1407
                    '.$iconTicket.'
1408
                </a>
1409
            </div>';
1410
        }
1411
1412
        $this->assign('bug_notification', $rightFloatMenu);
1413
1414
        return true;
1415
    }
1416
1417
    /**
1418
     * Prepare the _c array for template files. The _c array contains
1419
     * information about the current course.
1420
     */
1421
    private function set_course_parameters()
1422
    {
1423
        //Setting course id
1424
        $course = api_get_course_info();
1425
        if (empty($course)) {
1426
            $this->assign('course_is_set', false);
1427
1428
            return;
1429
        }
1430
        $this->assign('course_is_set', true);
1431
        $this->course_id = $course['id'];
1432
        $_c = [
1433
            'id' => $course['real_id'],
1434
            'code' => $course['code'],
1435
            'title' => $course['name'],
1436
            'visibility' => $course['visibility'],
1437
            'language' => $course['language'],
1438
            'directory' => $course['directory'],
1439
            'session_id' => api_get_session_id(),
1440
            'user_is_teacher' => api_is_course_admin(),
1441
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
1442
        ];
1443
        $this->assign('course_code', $course['code']);
1444
        $this->assign('_c', $_c);
1445
    }
1446
1447
    /**
1448
     * Prepare the _u array for template files. The _u array contains
1449
     * information about the current user, as returned by
1450
     * api_get_user_info().
1451
     */
1452
    private function set_user_parameters()
1453
    {
1454
        $user_info = [];
1455
        $user_info['logged'] = 0;
1456
        $this->user_is_logged_in = false;
1457
        if (api_user_is_login()) {
1458
            $user_info = api_get_user_info(api_get_user_id(), true);
1459
            $user_info['logged'] = 1;
1460
1461
            $user_info['is_admin'] = 0;
1462
            if (api_is_platform_admin()) {
1463
                $user_info['is_admin'] = 1;
1464
            }
1465
1466
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1467
            $this->user_is_logged_in = true;
1468
        }
1469
        // Setting the $_u array that could be use in any template
1470
        $this->assign('_u', $user_info);
1471
    }
1472
1473
    /**
1474
     * Set header parameters.
1475
     *
1476
     * @param bool $sendHeaders send headers
1477
     */
1478
    private function set_header_parameters($sendHeaders)
1479
    {
1480
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1481
        $_course = api_get_course_info();
1482
        $nameTools = $this->title;
1483
        $navigation = return_navigation_array();
1484
        $this->menu_navigation = $navigation['menu_navigation'];
1485
1486
        $this->assign('system_charset', api_get_system_encoding());
1487
1488
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1489
            foreach ($httpHeadXtra as &$thisHttpHead) {
1490
                //header($thisHttpHead);
1491
            }
1492
        }
1493
1494
        $this->assign(
1495
            'online_button',
1496
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
1497
        );
1498
        $this->assign(
1499
            'offline_button',
1500
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
1501
        );
1502
1503
        // Get language iso-code for this page - ignore errors
1504
        $this->assign('document_language', api_get_language_isocode());
1505
1506
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1507
1508
        $title_list = [];
1509
1510
        $title_list[] = api_get_setting('Institution');
1511
        $title_list[] = api_get_setting('siteName');
1512
1513
        if (!empty($course_title)) {
1514
            $title_list[] = $course_title;
1515
        }
1516
        if ($nameTools != '') {
1517
            $title_list[] = $nameTools;
1518
        }
1519
1520
        $title_string = '';
1521
        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...
1522
            $title_string .= $title_list[$i];
1523
            if (isset($title_list[$i + 1])) {
1524
                $item = trim($title_list[$i + 1]);
1525
                if (!empty($item)) {
1526
                    $title_string .= ' - ';
1527
                }
1528
            }
1529
        }
1530
1531
        $this->assign('title_string', $title_string);
1532
1533
        // Setting the theme and CSS files
1534
        $this->setCssFiles();
0 ignored issues
show
Deprecated Code introduced by
The function Template::setCssFiles() has been deprecated. ( Ignorable by Annotation )

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

1534
        /** @scrutinizer ignore-deprecated */ $this->setCssFiles();
Loading history...
1535
        $this->set_js_files();
1536
        $this->setCssCustomFiles();
1537
1538
        $browser = api_browser_support('check_browser');
1539
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1540
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1541
            $this->assign('browser_specific_head', $browser_head);
1542
        }
1543
1544
        // Implementation of prefetch.
1545
        // See http://cdn.chamilo.org/main/img/online.png for details
1546
        $prefetch = '';
1547
        if (!empty($_configuration['cdn_enable'])) {
1548
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1549
            foreach ($_configuration['cdn'] as $host => $exts) {
1550
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1551
            }
1552
        }
1553
1554
        $this->assign('prefetch', $prefetch);
1555
        $this->assign('text_direction', api_get_text_direction());
1556
        $this->assign('section_name', 'section-'.$this_section);
1557
1558
        $this->assignFavIcon(); //Set a 'favico' var for the template
1559
        $this->setHelp();
1560
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1561
1562
        // Preparing values for the menu
1563
1564
        // Logout link
1565
        $hideLogout = api_get_setting('hide_logout_button');
1566
        if ($hideLogout === 'true') {
1567
            $this->assign('logout_link', null);
1568
        } else {
1569
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1570
        }
1571
1572
        // Profile link
1573
        if (api_get_setting('allow_social_tool') == 'true') {
1574
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1575
        } else {
1576
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1577
        }
1578
1579
        $this->assign('profile_url', $profile_url);
1580
1581
        //Message link
1582
        $message_link = null;
1583
        $message_url = null;
1584
        if (api_get_setting('allow_message_tool') == 'true') {
1585
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1586
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1587
        }
1588
        $this->assign('message_link', $message_link);
1589
        $this->assign('message_url', $message_url);
1590
1591
        $pendingSurveyLink = '';
1592
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1593
        if ($show) {
1594
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1595
        }
1596
        $this->assign('pending_survey_url', $pendingSurveyLink);
1597
1598
        // Certificate Link
1599
        $allow = api_get_configuration_value('hide_my_certificate_link');
1600
        if ($allow === false) {
1601
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1602
            $certificateLink = Display::url(
1603
                get_lang('MyCertificates'),
1604
                $certificateUrl
1605
            );
1606
            $this->assign('certificate_link', $certificateLink);
1607
            $this->assign('certificate_url', $certificateUrl);
1608
        }
1609
1610
        $institution = api_get_setting('Institution');
1611
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1612
1613
        $this->assign('portal_name', $portal_name);
1614
1615
        //Menu
1616
        $menu = menuArray();
1617
        $this->assign('menu', $menu);
1618
1619
        $breadcrumb = '';
1620
        // Hide breadcrumb in LP
1621
        if ($this->show_learnpath == false) {
1622
            $breadcrumb = return_breadcrumb(
1623
                $interbreadcrumb,
1624
                $language_file,
1625
                $nameTools
1626
            );
1627
        }
1628
        $this->assign('breadcrumb', $breadcrumb);
1629
1630
        //Extra content
1631
        $extra_header = null;
1632
        if (!api_is_platform_admin()) {
1633
            $extra_header = trim(api_get_setting('header_extra_content'));
1634
        }
1635
        $this->assign('header_extra_content', $extra_header);
1636
1637
        if ($sendHeaders) {
1638
            /*header('Content-Type: text/html; charset='.api_get_system_encoding());
1639
            header(
1640
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1641
            );
1642
            self::addHTTPSecurityHeaders();*/
1643
1644
            $responseCode = $this->getResponseCode();
1645
            if (!empty($responseCode)) {
1646
                switch ($responseCode) {
1647
                    case '404':
1648
                        header("HTTP/1.0 404 Not Found");
1649
                        break;
1650
                }
1651
            }
1652
        }
1653
1654
        $socialMeta = '';
1655
        $metaTitle = api_get_setting('meta_title');
1656
        if (!empty($metaTitle)) {
1657
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1658
            $metaSite = api_get_setting('meta_twitter_site');
1659
            if (!empty($metaSite)) {
1660
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1661
                $metaCreator = api_get_setting('meta_twitter_creator');
1662
                if (!empty($metaCreator)) {
1663
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1664
                }
1665
            }
1666
1667
            // The user badge page emits its own meta tags, so if this is
1668
            // enabled, ignore the global ones
1669
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1670
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1671
1672
            if (!$userId && !$skillId) {
1673
                // no combination of user and skill ID has been defined,
1674
                // so print the normal OpenGraph meta tags
1675
                $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1676
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1677
1678
                $metaDescription = api_get_setting('meta_description');
1679
                if (!empty($metaDescription)) {
1680
                    $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1681
                }
1682
1683
                $metaImage = api_get_setting('meta_image_path');
1684
                if (!empty($metaImage)) {
1685
                    if (is_file(api_get_path(SYS_PATH).$metaImage)) {
1686
                        $path = api_get_path(WEB_PATH).$metaImage;
1687
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1688
                    }
1689
                }
1690
            }
1691
        }
1692
1693
        $this->assign('social_meta', $socialMeta);
1694
    }
1695
1696
    /**
1697
     * Set footer parameters.
1698
     */
1699
    private function set_footer_parameters()
1700
    {
1701
1702
1703
        // Loading footer extra content
1704
        if (!api_is_platform_admin()) {
1705
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1706
            if (!empty($extra_footer)) {
1707
                $this->assign('footer_extra_content', $extra_footer);
1708
            }
1709
        }
1710
1711
        // Tutor name
1712
1713
1714
    }
1715
1716
    /**
1717
     * Manage specific HTTP headers security.
1718
     */
1719
    private function addHTTPSecurityHeaders()
0 ignored issues
show
Unused Code introduced by
The method addHTTPSecurityHeaders() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1720
    {
1721
        // Implementation of HTTP headers security, as suggested and checked
1722
        // by https://securityheaders.io/
1723
        // Enable these settings in configuration.php to use them on your site
1724
        // Strict-Transport-Security
1725
        $setting = api_get_configuration_value('security_strict_transport');
1726
        if (!empty($setting)) {
1727
            header('Strict-Transport-Security: '.$setting);
1728
        }
1729
        // Content-Security-Policy
1730
        $setting = api_get_configuration_value('security_content_policy');
1731
        if (!empty($setting)) {
1732
            header('Content-Security-Policy: '.$setting);
1733
        }
1734
        $setting = api_get_configuration_value('security_content_policy_report_only');
1735
        if (!empty($setting)) {
1736
            header('Content-Security-Policy-Report-Only: '.$setting);
1737
        }
1738
        // Public-Key-Pins
1739
        $setting = api_get_configuration_value('security_public_key_pins');
1740
        if (!empty($setting)) {
1741
            header('Public-Key-Pins: '.$setting);
1742
        }
1743
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1744
        if (!empty($setting)) {
1745
            header('Public-Key-Pins-Report-Only: '.$setting);
1746
        }
1747
        // X-Frame-Options
1748
        $setting = api_get_configuration_value('security_x_frame_options');
1749
        if (!empty($setting)) {
1750
            header('X-Frame-Options: '.$setting);
1751
        }
1752
        // X-XSS-Protection
1753
        $setting = api_get_configuration_value('security_xss_protection');
1754
        if (!empty($setting)) {
1755
            header('X-XSS-Protection: '.$setting);
1756
        }
1757
        // X-Content-Type-Options
1758
        $setting = api_get_configuration_value('security_x_content_type_options');
1759
        if (!empty($setting)) {
1760
            header('X-Content-Type-Options: '.$setting);
1761
        }
1762
        // Referrer-Policy
1763
        $setting = api_get_configuration_value('security_referrer_policy');
1764
        if (!empty($setting)) {
1765
            header('Referrer-Policy: '.$setting);
1766
        }
1767
        // end of HTTP headers security block
1768
    }
1769
1770
    /**
1771
     * Assign favicon to the 'favico' template variable.
1772
     *
1773
     * @return bool Always return true because there is always at least one correct favicon.ico
1774
     */
1775
    private function assignFavIcon()
1776
    {
1777
        // Default root chamilo favicon
1778
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1779
1780
        //Added to verify if in the current Chamilo Theme exist a favicon
1781
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1782
1783
        //If exist pick the current chamilo theme favicon
1784
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1785
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1786
        }
1787
1788
        if (api_is_multiple_url_enabled()) {
1789
            $access_url_id = api_get_current_access_url_id();
1790
            if ($access_url_id != -1) {
1791
                $url_info = api_get_access_url($access_url_id);
1792
                $url = api_remove_trailing_slash(
1793
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1794
                );
1795
                $clean_url = api_replace_dangerous_char($url);
1796
                $clean_url = str_replace('/', '-', $clean_url);
1797
                $clean_url .= '/';
1798
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1799
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1800
                //we create the new dir for the new sites
1801
                if (is_file($icon_real_homep.'favicon.ico')) {
1802
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1803
                }
1804
            }
1805
        }
1806
1807
        $this->assign('favico', $favico);
1808
1809
        return true;
1810
    }
1811
1812
    /**
1813
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1814
     *
1815
     * @return bool Always return true (even if empty string)
1816
     */
1817
    private function assignSocialMeta()
0 ignored issues
show
Unused Code introduced by
The method assignSocialMeta() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
1818
    {
1819
        $socialMeta = '';
1820
        $metaTitle = api_get_setting('meta_title');
1821
        if (!empty($metaTitle)) {
1822
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1823
            $metaSite = api_get_setting('meta_twitter_site');
1824
            if (!empty($metaSite)) {
1825
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1826
                $metaCreator = api_get_setting('meta_twitter_creator');
1827
                if (!empty($metaCreator)) {
1828
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1829
                }
1830
            }
1831
1832
            // The user badge page emits its own meta tags, so if this is
1833
            // enabled, ignore the global ones
1834
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1835
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1836
1837
            if (!$userId && !$skillId) {
1838
                // no combination of user and skill ID has been defined,
1839
                // so print the normal or course-specific OpenGraph meta tags
1840
                // Check for a course ID
1841
                $courseId = api_get_course_int_id();
1842
                // Check session ID from session/id/about (see .htaccess)
1843
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1844
1845
                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...
1846
                    // If we are inside a course (even if within a session), publish info about the course
1847
                    $course = api_get_course_entity($courseId);
1848
                    // @TODO: support right-to-left in title
1849
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1850
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
1851
1852
                    $metaDescription = api_get_setting('meta_description');
1853
                    if (!empty($course->getDescription())) {
1854
                        $socialMeta .= '<meta property="og:description" content="'.$course->getDescription().'" />'."\n";
1855
                    } elseif (!empty($metaDescription)) {
1856
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1857
                    }
1858
1859
                    $picture = CourseManager::getPicturePath($course, true);
1860
                    if (!empty($picture)) {
1861
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1862
                    } else {
1863
                        $socialMeta .= $this->getMetaPortalImagePath();
1864
                    }
1865
                } elseif ($sessionId !== 0) {
1866
                    // If we are on a session "about" screen, publish info about the session
1867
                    $em = Database::getManager();
1868
                    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
1869
1870
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1871
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."session/{$session->getId()}/about/".'" />'."\n";
1872
1873
                    $sessionValues = new ExtraFieldValue('session');
1874
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1875
                    $sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1876
1877
                    if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
1878
                        $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
1879
                        $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1880
                    } else {
1881
                        $socialMeta .= $this->getMetaPortalImagePath();
1882
                    }
1883
                } else {
1884
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
1885
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1886
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1887
1888
                    $metaDescription = api_get_setting('meta_description');
1889
                    if (!empty($metaDescription)) {
1890
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1891
                    }
1892
                    $socialMeta .= $this->getMetaPortalImagePath();
1893
                }
1894
            }
1895
        }
1896
1897
        $this->assign('social_meta', $socialMeta);
1898
1899
        return true;
1900
    }
1901
1902
    /**
1903
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
1904
     *
1905
     * @return string The meta image HTML tag, or empty
1906
     */
1907
    private function getMetaPortalImagePath()
1908
    {
1909
        // Load portal meta image if defined
1910
        $metaImage = api_get_setting('meta_image_path');
1911
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
1912
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
1913
        $portalImageMeta = '';
1914
        if (!empty($metaImage)) {
1915
            if (is_file($metaImageSysPath)) {
1916
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
1917
            }
1918
        } else {
1919
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
1920
            if (!empty($logo)) {
1921
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
1922
            }
1923
        }
1924
1925
        return $portalImageMeta;
1926
    }
1927
}
1928