Completed
Push — master ( 44eeae...5e8909 )
by Julito
12:48
created

Template::assignFavIcon()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 35
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 19
nc 8
nop 0
dl 0
loc 35
rs 9.3222
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
        ];
96
97
        $urlId = api_get_current_access_url_id();
98
99
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
100
101
        if (!is_dir($cache_folder)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
102
            //mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
103
        }
104
105
        $loader = new Twig_Loader_Filesystem($template_paths);
106
107
        $isTestMode = api_get_setting('server_type') === 'test';
108
109
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
110
        if ($isTestMode) {
111
            $options = [
112
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
113
                'autoescape' => false,
114
                'debug' => true,
115
                'auto_reload' => true,
116
                'optimizations' => 0,
117
                // turn on optimizations with -1
118
                'strict_variables' => false,
119
                //If set to false, Twig will silently ignore invalid variables
120
            ];
121
        } else {
122
            $options = [
123
                'cache' => $cache_folder,
124
                //path to the cache folder
125
                'autoescape' => false,
126
                'debug' => false,
127
                'auto_reload' => false,
128
                'optimizations' => -1,
129
                // turn on optimizations with -1
130
                'strict_variables' => false,
131
                //If set to false, Twig will silently ignore invalid variables
132
            ];
133
        }
134
135
        $this->twig = new Twig_Environment($loader, $options);
136
137
        if ($isTestMode) {
138
            $this->twig->addExtension(new Twig_Extension_Debug());
139
        }
140
141
        // Twig filters setup
142
        $filters = [
143
            'get_plugin_lang',
144
            'get_lang',
145
            'api_get_path',
146
            'api_get_local_time',
147
            'api_convert_and_format_date',
148
            'api_is_allowed_to_edit',
149
            'api_get_user_info',
150
            'api_get_configuration_value',
151
            'api_get_setting',
152
            [
153
                'name' => 'return_message',
154
                'callable' => 'Display::return_message_and_translate',
155
            ],
156
            [
157
                'name' => 'display_page_header',
158
                'callable' => 'Display::page_header_and_translate',
159
            ],
160
            [
161
                'name' => 'display_page_subheader',
162
                'callable' => 'Display::page_subheader_and_translate',
163
            ],
164
            [
165
                'name' => 'icon',
166
                'callable' => 'Template::get_icon_path',
167
            ],
168
            [
169
                'name' => 'img',
170
                'callable' => 'Template::get_image',
171
            ],
172
            [
173
                'name' => 'format_date',
174
                'callable' => 'Template::format_date',
175
            ],
176
            [
177
                'name' => 'get_template',
178
                'callable' => 'Template::findTemplateFilePath',
179
            ],
180
            [
181
                'name' => 'date_to_time_ago',
182
                'callable' => 'Display::dateToStringAgoAndLongDate',
183
            ],
184
        ];
185
186
        foreach ($filters as $filter) {
187
            if (is_array($filter)) {
188
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
189
            } else {
190
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
191
            }
192
        }
193
194
        $functions = [
195
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
196
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
197
        ];
198
199
        foreach ($functions as $function) {
200
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
201
        }
202
203
        // Setting system variables
204
        $this->set_system_parameters();
205
206
        // Setting user variables
207
        $this->set_user_parameters();
208
209
        // Setting course variables
210
        $this->set_course_parameters();
211
212
        // Setting administrator variables
213
        $this->setAdministratorParams();
214
        //$this->setCSSEditor();
215
216
        // Header and footer are showed by default
217
        $this->set_footer($show_footer);
218
        $this->set_header($show_header);
219
220
        $this->set_header_parameters($sendHeaders);
221
        $this->set_footer_parameters();
222
223
        $defaultStyle = api_get_configuration_value('default_template');
224
        if (!empty($defaultStyle)) {
225
            $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...
226
        }
227
228
        $this->assign('template', $this->templateFolder);
229
        $this->assign('locale', api_get_language_isocode());
230
        $this->assign('login_class', null);
231
232
        $allow = api_get_configuration_value('show_language_selector_in_menu');
233
        if ($allow) {
234
            $this->assign('language_form', api_display_language_form());
235
        }
236
237
        // Chamilo plugins
238
        if ($this->show_header) {
239
            if ($this->load_plugins) {
240
                $this->plugin = new AppPlugin();
241
242
                //1. Showing installed plugins in regions
243
                $pluginRegions = $this->plugin->get_plugin_regions();
244
                foreach ($pluginRegions as $region) {
245
                    $this->set_plugin_region($region);
246
                }
247
248
                //2. Loading the course plugin info
249
                global $course_plugin;
250
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
251
                    //Load plugin get_langs
252
                    $this->plugin->load_plugin_lang_variables($course_plugin);
253
                }
254
            }
255
        }
256
    }
257
258
    /**
259
     * @param string $image
260
     * @param int    $size
261
     *
262
     * @return string
263
     */
264
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
265
    {
266
        return Display::return_icon($image, '', [], $size, false, true);
267
    }
268
269
    /**
270
     * @param string $image
271
     * @param int    $size
272
     * @param string $name
273
     *
274
     * @return string
275
     */
276
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
277
    {
278
        return Display::return_icon($image, $name, [], $size);
279
    }
280
281
    /**
282
     * @param string $timestamp
283
     * @param string $format
284
     *
285
     * @return string
286
     */
287
    public static function format_date($timestamp, $format = null)
288
    {
289
        return api_format_date($timestamp, $format);
290
    }
291
292
    /**
293
     * Return the item's url key:.
294
     *
295
     *      c_id=xx&id=xx
296
     *
297
     * @param object $item
298
     *
299
     * @return string
300
     */
301
    public static function key($item)
302
    {
303
        $id = isset($item->id) ? $item->id : null;
304
        $c_id = isset($item->c_id) ? $item->c_id : null;
305
        $result = '';
306
        if ($c_id) {
307
            $result = "c_id=$c_id";
308
        }
309
        if ($id) {
310
            if ($result) {
311
                $result .= "&amp;id=$id";
312
            } else {
313
                $result .= "&amp;id=$id";
314
            }
315
        }
316
317
        return $result;
318
    }
319
320
    /**
321
     * @param string $helpInput
322
     */
323
    public function setHelp($helpInput = null)
324
    {
325
        if (!empty($helpInput)) {
326
            $help = $helpInput;
327
        } else {
328
            $help = $this->help;
329
        }
330
331
        $content = '';
332
        if (api_get_setting('enable_help_link') == 'true') {
333
            if (!empty($help)) {
334
                $help = Security::remove_XSS($help);
335
                $content = '<div class="help">';
336
                $content .= Display::url(
337
                    Display::return_icon('help.large.png', get_lang('Help')),
338
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
339
                    [
340
                        'class' => 'ajax',
341
                        'data-title' => get_lang('Help'),
342
                    ]
343
                );
344
                $content .= '</div>';
345
            }
346
        }
347
        $this->assign('help_content', $content);
348
    }
349
350
    /**
351
     * Use template system to parse the actions menu.
352
     *
353
     * @todo finish it!
354
     */
355
    public function set_actions($actions)
356
    {
357
        $action_string = '';
358
        if (!empty($actions)) {
359
            foreach ($actions as $action) {
360
                $action_string .= $action;
361
            }
362
        }
363
        $this->assign('actions', $actions);
364
    }
365
366
    /**
367
     * Render the template.
368
     *
369
     * @param string $template           The template path
370
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
371
     */
372
    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

372
    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...
373
    {
374
        $template = str_replace('tpl', 'html.twig', $template);
375
        $templateFile = api_get_path(SYS_PATH).'main/template/'.$template;
376
377
        // Set legacy breadcrumb
378
        global $interbreadcrumb;
379
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
380
381
        if (!file_exists($templateFile)) {
382
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
383
            echo $e->getMessage();
384
            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...
385
        }
386
387
        $this->returnResponse($this->params, $template);
388
    }
389
390
    /**
391
     * @param array  $params
392
     * @param string $template
393
     *
394
     * @throws \Twig\Error\Error
395
     */
396
    public function returnResponse($params, $template)
397
    {
398
        $flash = Display::getFlashToString();
399
        Display::cleanFlashMessages();
400
        $response = new Response();
401
        $params['flash_messages'] = $flash;
402
        $content = Container::getTemplating()->render($template, $params);
403
        $response->setContent($content);
404
        $response->send();
405
    }
406
407
    /**
408
     * Shortcut to display a 1 col layout (index.php).
409
     * */
410
    public function display_one_col_template()
411
    {
412
        $template = '@ChamiloTheme/Layout/layout_one_col.html.twig';
413
        $this->returnResponse($this->params, $template);
414
    }
415
416
    /**
417
     * Shortcut to display a 2 col layout (userportal.php).
418
     */
419
    public function display_two_col_template()
420
    {
421
        $template = '@ChamiloTheme/Layout/layout_two_col.html.twig';
422
        $this->returnResponse($this->params, $template);
423
    }
424
425
    /**
426
     * Displays an empty template.
427
     */
428
    public function display_blank_template()
429
    {
430
        $template = '@ChamiloTheme/Layout/blank.html.twig';
431
        $this->returnResponse($this->params, $template);
432
    }
433
434
    /**
435
     * Displays an empty template.
436
     */
437
    public function displayBlankTemplateNoHeader()
438
    {
439
        $template = '@ChamiloTheme/Layout/blank_no_header.html.twig';
440
        $this->returnResponse($this->params, $template);
441
    }
442
443
    /**
444
     * Displays an empty template.
445
     */
446
    public function display_no_layout_template()
447
    {
448
        $template = '@ChamiloTheme/Layout/no_layout.html.twig';
449
        $this->returnResponse($this->params, $template);
450
    }
451
452
    /**
453
     * Displays an empty template.
454
     */
455
    public function displaySkillLayout()
456
    {
457
        $template = '@ChamiloTheme/Layout/skill_layout.html.twig';
458
        $this->returnResponse($this->params, $template);
459
    }
460
461
    /**
462
     * Sets the footer visibility.
463
     *
464
     * @param bool true if we show the footer
465
     */
466
    public function set_footer($status)
467
    {
468
        $this->show_footer = $status;
469
        $this->assign('show_footer', $status);
470
    }
471
472
    /**
473
     * return true if toolbar has to be displayed for user.
474
     *
475
     * @return bool
476
     */
477
    public static function isToolBarDisplayedForUser()
478
    {
479
        //Toolbar
480
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
481
        $show_toolbar = false;
482
483
        switch ($show_admin_toolbar) {
484
            case 'do_not_show':
485
                break;
486
            case 'show_to_admin':
487
                if (api_is_platform_admin()) {
488
                    $show_toolbar = true;
489
                }
490
                break;
491
            case 'show_to_admin_and_teachers':
492
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
493
                    $show_toolbar = true;
494
                }
495
                break;
496
            case 'show_to_all':
497
                $show_toolbar = true;
498
                break;
499
        }
500
501
        return $show_toolbar;
502
    }
503
504
    /**
505
     * Sets the header visibility.
506
     *
507
     * @param bool true if we show the header
508
     */
509
    public function set_header($status)
510
    {
511
        $this->show_header = $status;
512
        $this->assign('show_header', $status);
513
514
        $show_toolbar = 0;
515
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::show_navigation_tool_shortcuts();
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
        $_p = [
635
            'web' => api_get_path(WEB_PATH),
636
            'web_relative' => api_get_path(REL_PATH),
637
            'web_course' => api_get_path(WEB_COURSE_PATH),
638
            'web_main' => api_get_path(WEB_CODE_PATH),
639
            'web_css' => api_get_path(WEB_CSS_PATH),
640
            //'web_css_theme' => api_get_path(WEB_CSS_PATH) . 'themes/' . $this->theme . '/',
641
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
642
            'web_img' => api_get_path(WEB_IMG_PATH),
643
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
644
            'web_plugin_asset' => api_get_path(WEB_PLUGIN_ASSET_PATH),
645
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
646
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
647
            'web_self' => api_get_self(),
648
            'web_query_vars' => api_htmlentities($_SERVER['QUERY_STRING']),
649
            'web_self_query_vars' => api_htmlentities($_SERVER['REQUEST_URI']),
650
            'web_cid_query' => api_get_cidreq(),
651
        ];
652
653
        $_s = [
654
            'software_name' => api_get_configuration_value('software_name'),
655
            'system_version' => api_get_configuration_value('system_version'),
656
            'site_name' => api_get_setting('siteName'),
657
            'institution' => api_get_setting('Institution'),
658
            //'date' => api_format_date('now', DATE_FORMAT_LONG),
659
            'date' => '',
660
            'timezone' => '',
661
            //'timezone' => api_get_timezone(),
662
            'gamification_mode' => api_get_setting('gamification_mode'),
663
        ];
664
665
        //$user_info = api_get_user_info();
666
667
        return [
668
            '_p' => $_p,
669
            '_s' => $_s,
670
            //       '_u' => $user_info,
671
            'template' => 'default', // @todo setup template folder in config.yml;
672
        ];
673
    }
674
675
    /**
676
     * Set theme, include mainstream CSS files.
677
     *
678
     * @see setCssCustomFiles() for additional CSS sheets
679
     */
680
    public function setCssFiles()
681
    {
682
        global $disable_js_and_css_files;
683
        $css = [];
684
685
        // Default CSS Bootstrap
686
        $bowerCSSFiles = [
687
            'fontawesome/css/font-awesome.min.css',
688
            'jquery-ui/themes/smoothness/theme.css',
689
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
690
            'mediaelement/build/mediaelementplayer.min.css',
691
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
692
            'bootstrap/dist/css/bootstrap.min.css',
693
            'jquery.scrollbar/jquery.scrollbar.css',
694
            'bootstrap-daterangepicker/daterangepicker.css',
695
            'bootstrap-select/dist/css/bootstrap-select.min.css',
696
            'select2/dist/css/select2.min.css',
697
            'flag-icon-css/css/flag-icon.min.css',
698
            'mediaelement/plugins/vrview/vrview.css',
699
        ];
700
701
        $features = api_get_configuration_value('video_features');
702
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen', 'vrview'];
703
704
        if (!empty($features) && isset($features['features'])) {
705
            foreach ($features['features'] as $feature) {
706
                if ($feature === 'vrview') {
707
                    continue;
708
                }
709
                $bowerCSSFiles[] = "mediaelement/plugins/$feature/$feature.css";
710
                $defaultFeatures[] = $feature;
711
            }
712
        }
713
714
        foreach ($bowerCSSFiles as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
715
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
716
        }
717
718
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
719
720
        if (api_is_global_chat_enabled()) {
721
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
722
        }
723
        $css_file_to_string = '';
724
        foreach ($css as $file) {
725
            $css_file_to_string .= api_get_css($file);
726
        }
727
728
        if (!$disable_js_and_css_files) {
729
            $this->assign('css_static_file_to_string', $css_file_to_string);
730
        }
731
732
        $defaultFeatures = implode("','", $defaultFeatures);
733
        $this->assign('video_features', $defaultFeatures);
734
    }
735
736
    /**
737
     * Sets the "styles" menu in ckEditor.
738
     *
739
     * Reads css/themes/xxx/editor.css if exists and shows it in the menu, otherwise it
740
     * will take the default web/editor.css file
741
     */
742
    public function setStyleMenuInCkEditor()
743
    {
744
        $cssEditor = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'editor.css');
745
        if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'editor.css')) {
746
            $cssEditor = api_get_path(WEB_CSS_PATH).$this->themeDir.'editor.css';
747
        }
748
        $this->assign('css_editor', $cssEditor);
749
    }
750
751
    /**
752
     * Prepare custom CSS to be added at the very end of the <head> section.
753
     *
754
     * @see setCssFiles() for the mainstream CSS files
755
     */
756
    public function setCssCustomFiles()
757
    {
758
        global $disable_js_and_css_files;
759
        // chamilo CSS
760
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'../chamilo.css');
761
762
        // Base CSS
763
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.css');
764
        $css = [];
765
        if ($this->show_learnpath) {
766
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
767
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
768
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
769
            }
770
        }
771
772
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
773
        $css_file_to_string = '';
774
        foreach ($css as $file) {
775
            $css_file_to_string .= api_get_css($file);
776
        }
777
778
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
779
        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...
780
            //hack in order to fix the actions buttons
781
            $css_file_to_string .= '<style>
782
                .td_actions a {
783
                    float:left;
784
                    width:100%;
785
                }
786
                .forum_message_left a {
787
                    float:left;
788
                    width:100%;
789
                }
790
                </style>';
791
        }
792
793
        $navigator_info = api_get_navigator();
794
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
795
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
796
        }
797
798
        if (!$disable_js_and_css_files) {
799
            $this->assign('css_custom_file_to_string', $css_file_to_string);
800
801
            $style_print = '';
802
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
803
                $style_print = api_get_css(
804
                    api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->theme.'/print.css'),
805
                    'print'
806
                );
807
            }
808
            $this->assign('css_style_print', $style_print);
809
        }
810
811
        // Logo
812
        $logo = return_logo($this->theme);
813
        $this->assign('logo', $logo);
814
        $this->assign('show_media_element', 1);
815
    }
816
817
    /**
818
     * Declare and define the template variable that will be used to load
819
     * javascript libraries in the header.
820
     */
821
    public function set_js_files()
822
    {
823
        global $disable_js_and_css_files, $htmlHeadXtra;
824
        $isoCode = api_get_language_isocode();
825
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
826
827
        if ($isoCode == 'en') {
828
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
829
        }
830
        // JS files
831
        $js_files = [
832
            'chosen/chosen.jquery.min.js',
833
        ];
834
835
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
836
837
        if (api_is_global_chat_enabled() || $viewBySession) {
838
            // Do not include the global chat in LP
839
            if ($this->show_learnpath == false &&
840
                $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...
841
                $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...
842
            ) {
843
                $js_files[] = 'chat/js/chat.js';
844
            }
845
        }
846
847
        if (api_get_setting('accessibility_font_resize') === 'true') {
848
            $js_files[] = 'fontresize.js';
849
        }
850
851
        $js_file_to_string = '';
852
        $bowerJsFiles = [
853
            'modernizr/modernizr.js',
854
            'jquery/dist/jquery.min.js',
855
            'bootstrap/dist/js/bootstrap.min.js',
856
            'jquery-ui/jquery-ui.min.js',
857
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
858
            'moment/min/moment-with-locales.js',
859
            'bootstrap-daterangepicker/daterangepicker.js',
860
            'jquery-timeago/jquery.timeago.js',
861
            'mediaelement/build/mediaelement-and-player.min.js',
862
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
863
            'image-map-resizer/js/imageMapResizer.min.js',
864
            'jquery.scrollbar/jquery.scrollbar.min.js',
865
            //'readmore-js/readmore.min.js',
866
            'bootstrap-select/dist/js/bootstrap-select.min.js',
867
            $selectLink,
868
            'select2/dist/js/select2.min.js',
869
            "select2/dist/js/i18n/$isoCode.js",
870
            'mediaelement/plugins/vrview/vrview.js',
871
        ];
872
873
        $features = api_get_configuration_value('video_features');
874
        if (!empty($features) && isset($features['features'])) {
875
            foreach ($features['features'] as $feature) {
876
                if ($feature === 'vrview') {
877
                    continue;
878
                }
879
                $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js";
880
            }
881
        }
882
883
        if (CHAMILO_LOAD_WYSIWYG === true) {
884
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
885
        }
886
887
        if (api_get_setting('include_asciimathml_script') === 'true') {
888
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
889
        }
890
891
        if ($isoCode != 'en') {
892
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
893
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
894
        }
895
896
        foreach ($bowerJsFiles as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
897
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
898
        }
899
900
        foreach ($js_files as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
901
            //$js_file_to_string .= api_get_js($file);
902
        }
903
904
        // Loading email_editor js
905
        if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') {
906
            $template = $this->get_template('mail_editor/email_link.js.tpl');
907
            $js_file_to_string .= $this->fetch($template);
908
        }
909
910
        if (!$disable_js_and_css_files) {
911
            $this->assign('js_file_to_string', $js_file_to_string);
912
913
            $extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
914
            //Adding jquery ui by default
915
            $extraHeaders .= api_get_jquery_ui_js();
916
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
917
                foreach ($htmlHeadXtra as &$this_html_head) {
918
                    $extraHeaders .= $this_html_head."\n";
919
                }
920
            }
921
922
            $ajax = api_get_path(WEB_AJAX_PATH);
923
            $courseId = api_get_course_id();
924
            if (empty($courseId)) {
925
                $courseLogoutCode = '
926
                <script>
927
                function courseLogout() {
928
                }
929
                </script>';
930
            } else {
931
                $courseLogoutCode = "
932
                <script>
933
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
934
                function courseLogout() {                
935
                    $.ajax({
936
                        async : false,
937
                        url: logOutUrl,
938
                        success: function (data) {
939
                            return 1;
940
                        }
941
                    });
942
                }
943
                </script>";
944
            }
945
946
            $extraHeaders .= $courseLogoutCode;
947
            $this->assign('extra_headers', $extraHeaders);
948
        }
949
    }
950
951
    /**
952
     * Special function to declare last-minute JS libraries which depend on
953
     * other things to be declared first. In particular, it might be useful
954
     * under IE9 with compatibility mode, which for some reason is getting
955
     * upset when a variable is used in a function (even if not used yet)
956
     * when this variable hasn't been defined yet.
957
     */
958
    public function set_js_files_post()
959
    {
960
        global $disable_js_and_css_files;
961
        $js_files = [];
962
        if (api_is_global_chat_enabled()) {
963
            //Do not include the global chat in LP
964
            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...
965
                $js_files[] = 'chat/js/chat.js';
966
            }
967
        }
968
        $js_file_to_string = '';
969
        foreach ($js_files as $js_file) {
970
            $js_file_to_string .= api_get_js($js_file);
971
        }
972
        if (!$disable_js_and_css_files) {
973
            $this->assign('js_file_to_string_post', $js_file_to_string);
974
        }
975
    }
976
977
    /**
978
     * @param string $theme
979
     *
980
     * @return string
981
     */
982
    public static function getPortalIcon($theme)
983
    {
984
        // Default root chamilo favicon
985
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
986
987
        // Added to verify if in the current Chamilo Theme exist a favicon
988
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).'/themes/'.$theme.'/images/';
989
990
        //If exist pick the current chamilo theme favicon
991
        if (is_file($favicoThemeUrl.'favicon.ico')) {
992
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).'themes/'.$theme.'/images/favicon.ico" type="image/x-icon" />';
993
        }
994
        if (api_is_multiple_url_enabled()) {
995
            $access_url_id = api_get_current_access_url_id();
996
            if ($access_url_id != -1) {
997
                $url_info = api_get_access_url($access_url_id);
998
                $url = api_remove_trailing_slash(
999
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1000
                );
1001
                $clean_url = api_replace_dangerous_char($url);
1002
                $clean_url = str_replace('/', '-', $clean_url);
1003
                $clean_url .= '/';
1004
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1005
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1006
                //we create the new dir for the new sites
1007
                if (is_file($icon_real_homep.'favicon.ico')) {
1008
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1009
                }
1010
            }
1011
        }
1012
1013
        //var_dump(Container::$container->get('router')->generate('main', ['name' => '1']));
1014
        //var_dump(api_get_path(WEB_PATH));
1015
1016
        return $favico;
1017
    }
1018
1019
    /**
1020
     * Show header template.
1021
     */
1022
    public function show_header_template()
1023
    {
1024
        $tpl = $this->get_template('layout/show_header.tpl');
1025
        $this->display($tpl);
1026
    }
1027
1028
    /**
1029
     * Show footer template.
1030
     */
1031
    public function show_footer_template()
1032
    {
1033
        $tpl = $this->get_template('layout/show_footer.tpl');
1034
        $this->display($tpl);
1035
    }
1036
1037
    /**
1038
     * Show footer js template.
1039
     */
1040
    public function show_footer_js_template()
1041
    {
1042
        $tpl = $this->get_template('layout/footer.js.tpl');
1043
        $this->display($tpl);
1044
    }
1045
1046
    /**
1047
     * Sets the plugin content in a template variable.
1048
     *
1049
     * @param string $pluginRegion
1050
     */
1051
    public function set_plugin_region($pluginRegion)
1052
    {
1053
        if (!empty($pluginRegion)) {
1054
            $regionContent = $this->plugin->load_region(
1055
                $pluginRegion,
1056
                $this,
1057
                $this->force_plugin_load
1058
            );
1059
1060
            $pluginList = $this->plugin->get_installed_plugins();
1061
            foreach ($pluginList as $plugin_name) {
1062
                // The plugin_info variable is available inside the plugin index
1063
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
1064
1065
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
1066
                    $courseInfo = api_get_course_info();
1067
                    if (!empty($courseInfo)) {
1068
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
1069
                            /** @var Plugin $plugin */
1070
                            $plugin = $pluginInfo['obj'];
1071
                            $regionContent .= $plugin->renderRegion($pluginRegion);
1072
                        }
1073
                    }
1074
                } else {
1075
                    continue;
1076
                }
1077
            }
1078
1079
            if (!empty($regionContent)) {
1080
                $this->assign('plugin_'.$pluginRegion, $regionContent);
1081
            } else {
1082
                $this->assign('plugin_'.$pluginRegion, null);
1083
            }
1084
        }
1085
1086
        return null;
1087
    }
1088
1089
    /**
1090
     * @param string $template
1091
     *
1092
     * @return string
1093
     */
1094
    public function fetch($template = null)
1095
    {
1096
        $template = $this->twig->loadTemplate($template);
1097
1098
        return $template->render($this->params);
1099
    }
1100
1101
    /**
1102
     * @param string $variable
1103
     * @param mixed  $value
1104
     */
1105
    public function assign($variable, $value = '')
1106
    {
1107
        $this->params[$variable] = $value;
1108
    }
1109
1110
    /**
1111
     * Adds a body class for login pages.
1112
     */
1113
    public function setLoginBodyClass()
1114
    {
1115
        $this->assign('login_class', 'section-login');
1116
    }
1117
1118
    /**
1119
     * The theme that will be used if the database is not working.
1120
     *
1121
     * @return string
1122
     */
1123
    public static function getThemeFallback()
1124
    {
1125
        $theme = api_get_configuration_value('theme_fallback');
1126
        if (empty($theme)) {
1127
            $theme = 'chamilo';
1128
        }
1129
1130
        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...
1131
    }
1132
1133
    /**
1134
     * @param bool|true $setLoginForm
1135
     */
1136
    public function setLoginForm($setLoginForm = true)
1137
    {
1138
        global $loginFailed;
1139
        $userId = api_get_user_id();
1140
        if (!($userId) || api_is_anonymous($userId)) {
1141
            // Only display if the user isn't logged in.
1142
            $this->assign(
1143
                'login_language_form',
1144
                api_display_language_form(true, true)
1145
            );
1146
            if ($setLoginForm) {
1147
                $this->assign('login_form', $this->displayLoginForm());
1148
1149
                if ($loginFailed) {
1150
                    $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

1150
                    $this->assign('login_failed', $this::/** @scrutinizer ignore-call */ handleLoginFailed());
Loading history...
1151
                }
1152
            }
1153
        }
1154
    }
1155
1156
    /**
1157
     * @return string
1158
     */
1159
    public function handleLoginFailed()
1160
    {
1161
        $message = get_lang('InvalidId');
1162
1163
        if (!isset($_GET['error'])) {
1164
            if (api_is_self_registration_allowed()) {
1165
                $message = get_lang('InvalidForSelfRegistration');
1166
            }
1167
        } else {
1168
            switch ($_GET['error']) {
1169
                case '':
1170
                    if (api_is_self_registration_allowed()) {
1171
                        $message = get_lang('InvalidForSelfRegistration');
1172
                    }
1173
                    break;
1174
                case 'account_expired':
1175
                    $message = get_lang('AccountExpired');
1176
                    break;
1177
                case 'account_inactive':
1178
                    $message = get_lang('AccountInactive');
1179
1180
                    if (api_get_setting('allow_registration') === 'confirmation') {
1181
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1182
                        $message .= Display::url(
1183
                            get_lang('ReSendConfirmationMail'),
1184
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1185
                            ['class' => 'alert-link']
1186
                        );
1187
                    }
1188
                    break;
1189
                case 'user_password_incorrect':
1190
                    $message = get_lang('InvalidId');
1191
                    break;
1192
                case 'access_url_inactive':
1193
                    $message = get_lang('AccountURLInactive');
1194
                    break;
1195
                case 'wrong_captcha':
1196
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1197
                    break;
1198
                case 'blocked_by_captcha':
1199
                    $message = get_lang('AccountBlockedByCaptcha');
1200
                    break;
1201
                case 'multiple_connection_not_allowed':
1202
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1203
                    break;
1204
                case 'unrecognize_sso_origin':
1205
                    //$message = get_lang('SSOError');
1206
                    break;
1207
            }
1208
        }
1209
1210
        return Display::return_message($message, 'error', false);
1211
    }
1212
1213
    /**
1214
     * @return string
1215
     */
1216
    public function displayLoginForm()
1217
    {
1218
        $form = new FormValidator(
1219
            'form-login',
1220
            'POST',
1221
            api_get_path(WEB_PUBLIC_PATH).'login_check',
1222
            null,
1223
            null,
1224
            FormValidator::LAYOUT_BOX_NO_LABEL
1225
        );
1226
        $params = [
1227
            'id' => '_username',
1228
            'autofocus' => 'autofocus',
1229
            'icon' => 'user fa-fw',
1230
            'placeholder' => get_lang('UserName'),
1231
        ];
1232
        $browserAutoCapitalize = false;
1233
        // Avoid showing the autocapitalize option if the browser doesn't
1234
        // support it: this attribute is against the HTML5 standard
1235
        if (api_browser_support('autocapitalize')) {
1236
            $browserAutoCapitalize = false;
1237
            $params['autocapitalize'] = 'none';
1238
        }
1239
        $form->addText(
1240
            '_username',
1241
            get_lang('UserName'),
1242
            true,
1243
            $params
1244
        );
1245
        $params = [
1246
            'id' => '_password',
1247
            'icon' => 'lock fa-fw',
1248
            'placeholder' => get_lang('Pass'),
1249
        ];
1250
        if ($browserAutoCapitalize) {
1251
            $params['autocapitalize'] = 'none';
1252
        }
1253
        $form->addElement(
1254
            'password',
1255
            '_password',
1256
            get_lang('Pass'),
1257
            $params
1258
        );
1259
1260
        $token = Chamilo\CoreBundle\Framework\Container::$container->get('security.csrf.token_manager')->getToken('authenticate');
1261
        $form->addHidden('_csrf_token', $token->getValue());
1262
1263
        // Captcha
1264
        $captcha = api_get_setting('allow_captcha');
1265
        $allowCaptcha = $captcha === 'true';
1266
1267
        if ($allowCaptcha) {
1268
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1269
            if ($useCaptcha) {
1270
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1271
                $options = [
1272
                    'width' => 250,
1273
                    'height' => 90,
1274
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1275
                    'sessionVar' => basename(__FILE__, '.php'),
1276
                    'imageOptions' => [
1277
                        'font_size' => 20,
1278
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1279
                        'font_file' => 'OpenSans-Regular.ttf',
1280
                        //'output' => 'gif'
1281
                    ],
1282
                ];
1283
1284
                // Minimum options using all defaults (including defaults for Image_Text):
1285
                //$options = array('callback' => 'qfcaptcha_image.php');
1286
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1287
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1288
1289
                $form->addElement(
1290
                    'text',
1291
                    'captcha',
1292
                    get_lang('EnterTheLettersYouSee')
1293
                );
1294
                $form->addRule(
1295
                    'captcha',
1296
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1297
                    'required',
1298
                    null,
1299
                    'client'
1300
                );
1301
                $form->addRule(
1302
                    'captcha',
1303
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1304
                    'CAPTCHA',
1305
                    $captcha_question
1306
                );
1307
            }
1308
        }
1309
1310
        $form->addButton(
1311
            'submitAuth',
1312
            get_lang('LoginEnter'),
1313
            null,
1314
            'primary',
1315
            null,
1316
            'btn-block'
1317
        );
1318
1319
        $html = $form->returnForm();
1320
        if (api_get_setting('openid_authentication') == 'true') {
1321
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1322
            $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

1322
            $html .= '<div>'./** @scrutinizer ignore-call */ openid_form().'</div>';
Loading history...
1323
        }
1324
1325
        return $html;
1326
    }
1327
1328
    /**
1329
     * Returns the tutors names for the current course in session
1330
     * Function to use in Twig templates.
1331
     *
1332
     * @return string
1333
     */
1334
    public static function returnTutorsNames()
1335
    {
1336
        $em = Database::getManager();
1337
        $tutors = $em
1338
            ->createQuery('
1339
                SELECT u FROM ChamiloUserBundle:User u
1340
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1341
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1342
            ')
1343
            ->setParameters([
1344
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1345
                'session' => api_get_session_id(),
1346
                'course' => api_get_course_int_id(),
1347
            ])
1348
            ->getResult();
1349
1350
        $names = [];
1351
1352
        /** @var User $tutor */
1353
        foreach ($tutors as $tutor) {
1354
            $names[] = $tutor->getCompleteName();
1355
        }
1356
1357
        return implode(CourseManager::USER_SEPARATOR, $names);
1358
    }
1359
1360
    /*s
1361
     * Returns the teachers name for the current course
1362
     * Function to use in Twig templates
1363
     * @return string
1364
     */
1365
    public static function returnTeachersNames()
1366
    {
1367
        $em = Database::getManager();
1368
        $teachers = $em
1369
            ->createQuery('
1370
                SELECT u FROM ChamiloUserBundle:User u
1371
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1372
                WHERE cu.status = :teacher_status AND cu.course = :course
1373
            ')
1374
            ->setParameters([
1375
                'teacher_status' => User::COURSE_MANAGER,
1376
                'course' => api_get_course_int_id(),
1377
            ])
1378
            ->getResult();
1379
1380
        $names = [];
1381
1382
        /** @var User $teacher */
1383
        foreach ($teachers as $teacher) {
1384
            $names[] = $teacher->getCompleteName();
1385
        }
1386
1387
        return implode(CourseManager::USER_SEPARATOR, $names);
1388
    }
1389
1390
    /**
1391
     * @param int $code
1392
     */
1393
    public function setResponseCode($code)
1394
    {
1395
        $this->responseCode = $code;
1396
    }
1397
1398
    /**
1399
     * @param string $code
1400
     */
1401
    public function getResponseCode()
1402
    {
1403
        return $this->responseCode;
1404
    }
1405
1406
    /**
1407
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1408
     *
1409
     * @return bool Always return true because there is always a string, even if empty
1410
     */
1411
    public function assignBugNotification()
1412
    {
1413
        //@todo move this in the template
1414
        $rightFloatMenu = '';
1415
        $iconBug = Display::return_icon(
1416
            'bug.png',
1417
            get_lang('ReportABug'),
1418
            [],
1419
            ICON_SIZE_LARGE
1420
        );
1421
        if (api_get_setting('show_link_bug_notification') === 'true' && $this->user_is_logged_in) {
1422
            $rightFloatMenu = '<div class="report">
1423
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1424
                    '.$iconBug.'
1425
                </a>
1426
		        </div>';
1427
        }
1428
1429
        if (api_get_setting('show_link_ticket_notification') === 'true' &&
1430
            $this->user_is_logged_in
1431
        ) {
1432
            // by default is project_id = 1
1433
            $defaultProjectId = 1;
1434
            $iconTicket = Display::return_icon(
1435
                'help.png',
1436
                get_lang('Ticket'),
1437
                [],
1438
                ICON_SIZE_LARGE
1439
            );
1440
            $courseInfo = api_get_course_info();
1441
            $courseParams = '';
1442
            if (!empty($courseInfo)) {
1443
                $courseParams = api_get_cidreq();
1444
            }
1445
            $url = api_get_path(WEB_CODE_PATH).
1446
                'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams;
1447
            $rightFloatMenu .= '<div class="help">
1448
                <a href="'.$url.'" target="_blank">
1449
                    '.$iconTicket.'
1450
                </a>
1451
            </div>';
1452
        }
1453
1454
        $this->assign('bug_notification', $rightFloatMenu);
1455
1456
        return true;
1457
    }
1458
1459
    /**
1460
     * Prepare the _c array for template files. The _c array contains
1461
     * information about the current course.
1462
     */
1463
    private function set_course_parameters()
1464
    {
1465
        //Setting course id
1466
        $course = api_get_course_info();
1467
        if (empty($course)) {
1468
            $this->assign('course_is_set', false);
1469
1470
            return;
1471
        }
1472
        $this->assign('course_is_set', true);
1473
        $this->course_id = $course['id'];
1474
        $_c = [
1475
            'id' => $course['real_id'],
1476
            'code' => $course['code'],
1477
            'title' => $course['name'],
1478
            'visibility' => $course['visibility'],
1479
            'language' => $course['language'],
1480
            'directory' => $course['directory'],
1481
            'session_id' => api_get_session_id(),
1482
            'user_is_teacher' => api_is_course_admin(),
1483
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
1484
        ];
1485
        $this->assign('course_code', $course['code']);
1486
        $this->assign('_c', $_c);
1487
    }
1488
1489
    /**
1490
     * Prepare the _u array for template files. The _u array contains
1491
     * information about the current user, as returned by
1492
     * api_get_user_info().
1493
     */
1494
    private function set_user_parameters()
1495
    {
1496
        $user_info = [];
1497
        $user_info['logged'] = 0;
1498
        $this->user_is_logged_in = false;
1499
        if (api_user_is_login()) {
1500
            $user_info = api_get_user_info(api_get_user_id(), true);
1501
            $user_info['logged'] = 1;
1502
1503
            $user_info['is_admin'] = 0;
1504
            if (api_is_platform_admin()) {
1505
                $user_info['is_admin'] = 1;
1506
            }
1507
1508
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1509
            $this->user_is_logged_in = true;
1510
        }
1511
        // Setting the $_u array that could be use in any template
1512
        $this->assign('_u', $user_info);
1513
    }
1514
1515
    /**
1516
     * Get an array of all the web paths available (e.g. 'web' => 'https://my.chamilo.site/').
1517
     *
1518
     * @return array
1519
     */
1520
    private function getWebPaths()
1521
    {
1522
        $queryString = empty($_SERVER['QUERY_STRING']) ? '' : $_SERVER['QUERY_STRING'];
1523
        $requestURI = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
1524
1525
        return [
1526
            'web' => api_get_path(WEB_PATH),
1527
            'web_url' => api_get_web_url(),
1528
            'web_relative' => api_get_path(REL_PATH),
1529
            'web_course' => api_get_path(WEB_COURSE_PATH),
1530
            'web_main' => api_get_path(WEB_CODE_PATH),
1531
            'web_css' => api_get_path(WEB_CSS_PATH),
1532
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
1533
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
1534
            'web_img' => api_get_path(WEB_IMG_PATH),
1535
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
1536
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
1537
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
1538
            'web_self' => api_get_self(),
1539
            'web_query_vars' => api_htmlentities($queryString),
1540
            'web_self_query_vars' => api_htmlentities($requestURI),
1541
            'web_cid_query' => api_get_cidreq(),
1542
            'web_rel_code' => api_get_path(REL_CODE_PATH),
1543
        ];
1544
    }
1545
1546
    /**
1547
     * Set header parameters.
1548
     *
1549
     * @param bool $sendHeaders send headers
1550
     */
1551
    private function set_header_parameters($sendHeaders)
1552
    {
1553
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1554
        $_course = api_get_course_info();
1555
        $nameTools = $this->title;
1556
        $navigation = return_navigation_array();
1557
        $this->menu_navigation = $navigation['menu_navigation'];
1558
1559
        $this->assign('system_charset', api_get_system_encoding());
1560
1561
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1562
            foreach ($httpHeadXtra as &$thisHttpHead) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
1563
                //header($thisHttpHead);
1564
            }
1565
        }
1566
1567
        $this->assign(
1568
            'online_button',
1569
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
1570
        );
1571
        $this->assign(
1572
            'offline_button',
1573
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
1574
        );
1575
1576
        // Get language iso-code for this page - ignore errors
1577
        $this->assign('document_language', api_get_language_isocode());
1578
1579
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1580
1581
        $title_list = [];
1582
1583
        $title_list[] = api_get_setting('Institution');
1584
        $title_list[] = api_get_setting('siteName');
1585
1586
        if (!empty($course_title)) {
1587
            $title_list[] = $course_title;
1588
        }
1589
        if ($nameTools != '') {
1590
            $title_list[] = $nameTools;
1591
        }
1592
1593
        $title_string = '';
1594
        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...
1595
            $title_string .= $title_list[$i];
1596
            if (isset($title_list[$i + 1])) {
1597
                $item = trim($title_list[$i + 1]);
1598
                if (!empty($item)) {
1599
                    $title_string .= ' - ';
1600
                }
1601
            }
1602
        }
1603
1604
        $this->assign('title_string', $title_string);
1605
1606
        // Setting the theme and CSS files
1607
        $this->setCssFiles();
1608
        $this->set_js_files();
1609
        $this->setCssCustomFiles();
1610
1611
        $browser = api_browser_support('check_browser');
1612
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1613
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1614
            $this->assign('browser_specific_head', $browser_head);
1615
        }
1616
1617
        // Implementation of prefetch.
1618
        // See http://cdn.chamilo.org/main/img/online.png for details
1619
        $prefetch = '';
1620
        if (!empty($_configuration['cdn_enable'])) {
1621
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1622
            foreach ($_configuration['cdn'] as $host => $exts) {
1623
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1624
            }
1625
        }
1626
1627
        $this->assign('prefetch', $prefetch);
1628
        $this->assign('text_direction', api_get_text_direction());
1629
        $this->assign('section_name', 'section-'.$this_section);
1630
1631
        $this->assignFavIcon(); //Set a 'favico' var for the template
1632
        $this->setHelp();
1633
1634
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1635
1636
        $this->assignAccessibilityBlock(); //Prepare the 'accessibility' var for the template
1637
1638
        // Preparing values for the menu
1639
1640
        // Logout link
1641
        $hideLogout = api_get_setting('hide_logout_button');
1642
        if ($hideLogout === 'true') {
1643
            $this->assign('logout_link', null);
1644
        } else {
1645
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1646
        }
1647
1648
        // Profile link
1649
        if (api_get_setting('allow_social_tool') == 'true') {
1650
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1651
        } else {
1652
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1653
        }
1654
1655
        $this->assign('profile_url', $profile_url);
1656
1657
        //Message link
1658
        $message_link = null;
1659
        $message_url = null;
1660
        if (api_get_setting('allow_message_tool') == 'true') {
1661
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1662
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1663
        }
1664
        $this->assign('message_link', $message_link);
1665
        $this->assign('message_url', $message_url);
1666
1667
        $pendingSurveyLink = '';
1668
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1669
        if ($show) {
1670
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1671
        }
1672
        $this->assign('pending_survey_url', $pendingSurveyLink);
1673
1674
        // Certificate Link
1675
        $allow = api_get_configuration_value('hide_my_certificate_link');
1676
        if ($allow === false) {
1677
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1678
            $certificateLink = Display::url(
1679
                get_lang('MyCertificates'),
1680
                $certificateUrl
1681
            );
1682
            $this->assign('certificate_link', $certificateLink);
1683
            $this->assign('certificate_url', $certificateUrl);
1684
        }
1685
1686
        $institution = api_get_setting('Institution');
1687
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1688
1689
        $this->assign('portal_name', $portal_name);
1690
1691
        //Menu
1692
        $menu = menuArray();
1693
        $this->assign('menu', $menu);
1694
1695
        $breadcrumb = '';
1696
        // Hide breadcrumb in LP
1697
        if ($this->show_learnpath == false) {
1698
            $breadcrumb = return_breadcrumb(
1699
                $interbreadcrumb,
1700
                $language_file,
1701
                $nameTools
1702
            );
1703
        }
1704
        $this->assign('breadcrumb', $breadcrumb);
1705
1706
        //Extra content
1707
        $extra_header = null;
1708
        if (!api_is_platform_admin()) {
1709
            $extra_header = trim(api_get_setting('header_extra_content'));
1710
        }
1711
        $this->assign('header_extra_content', $extra_header);
1712
1713
        if ($sendHeaders) {
1714
            /*header('Content-Type: text/html; charset='.api_get_system_encoding());
1715
            header(
1716
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1717
            );
1718
            self::addHTTPSecurityHeaders();*/
1719
1720
            $responseCode = $this->getResponseCode();
1721
            if (!empty($responseCode)) {
1722
                switch ($responseCode) {
1723
                    case '404':
1724
                        header("HTTP/1.0 404 Not Found");
1725
                        break;
1726
                }
1727
            }
1728
        }
1729
1730
        $socialMeta = '';
1731
        $metaTitle = api_get_setting('meta_title');
1732
        if (!empty($metaTitle)) {
1733
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1734
            $metaSite = api_get_setting('meta_twitter_site');
1735
            if (!empty($metaSite)) {
1736
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1737
                $metaCreator = api_get_setting('meta_twitter_creator');
1738
                if (!empty($metaCreator)) {
1739
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1740
                }
1741
            }
1742
1743
            // The user badge page emits its own meta tags, so if this is
1744
            // enabled, ignore the global ones
1745
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1746
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1747
1748
            if (!$userId && !$skillId) {
1749
                // no combination of user and skill ID has been defined,
1750
                // so print the normal OpenGraph meta tags
1751
                $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1752
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1753
1754
                $metaDescription = api_get_setting('meta_description');
1755
                if (!empty($metaDescription)) {
1756
                    $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1757
                }
1758
1759
                $metaImage = api_get_setting('meta_image_path');
1760
                if (!empty($metaImage)) {
1761
                    if (is_file(api_get_path(SYS_PATH).$metaImage)) {
1762
                        $path = api_get_path(WEB_PATH).$metaImage;
1763
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1764
                    }
1765
                }
1766
            }
1767
        }
1768
1769
        $this->assign('social_meta', $socialMeta);
1770
    }
1771
1772
    /**
1773
     * Set footer parameters.
1774
     */
1775
    private function set_footer_parameters()
1776
    {
1777
        if (api_get_setting('show_administrator_data') === 'true') {
1778
            $firstName = api_get_setting('administratorName');
1779
            $lastName = api_get_setting('administratorSurname');
1780
1781
            if (!empty($firstName) && !empty($lastName)) {
1782
                $name = api_get_person_name($firstName, $lastName);
1783
            } else {
1784
                $name = $lastName;
1785
                if (empty($lastName)) {
1786
                    $name = $firstName;
1787
                }
1788
            }
1789
1790
            $adminName = '';
1791
            // Administrator name
1792
            if (!empty($name)) {
1793
                $adminName = get_lang('Manager').' : '.
1794
                    Display::encrypted_mailto_link(
1795
                        api_get_setting('emailAdministrator'),
1796
                        $name
1797
                    );
1798
            }
1799
            $this->assign('administrator_name', $adminName);
1800
        }
1801
1802
        // Loading footer extra content
1803
        if (!api_is_platform_admin()) {
1804
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1805
            if (!empty($extra_footer)) {
1806
                $this->assign('footer_extra_content', $extra_footer);
1807
            }
1808
        }
1809
1810
        // Tutor name
1811
        if (api_get_setting('show_tutor_data') == 'true') {
1812
            // Course manager
1813
            $courseId = api_get_course_int_id();
1814
            $id_session = api_get_session_id();
1815
            if (!empty($courseId)) {
1816
                $tutor_data = '';
1817
                if ($id_session != 0) {
1818
                    $coachs_email = CourseManager::get_email_of_tutor_to_session(
1819
                        $id_session,
1820
                        $courseId
1821
                    );
1822
                    $email_link = [];
1823
                    foreach ($coachs_email as $coach) {
1824
                        $email_link[] = Display::encrypted_mailto_link($coach['email'], $coach['complete_name']);
1825
                    }
1826
                    if (count($coachs_email) > 1) {
1827
                        $tutor_data .= get_lang('Coachs').' : ';
1828
                        $tutor_data .= array_to_string($email_link, CourseManager::USER_SEPARATOR);
1829
                    } elseif (count($coachs_email) == 1) {
1830
                        $tutor_data .= get_lang('Coach').' : ';
1831
                        $tutor_data .= array_to_string($email_link, CourseManager::USER_SEPARATOR);
1832
                    } elseif (count($coachs_email) == 0) {
1833
                        $tutor_data .= '';
1834
                    }
1835
                }
1836
                $this->assign('session_teachers', $tutor_data);
1837
            }
1838
        }
1839
1840
        if (api_get_setting('show_teacher_data') == 'true') {
1841
            // course manager
1842
            $courseId = api_get_course_int_id();
1843
            if (!empty($courseId)) {
1844
                $teacher_data = '';
1845
                $mail = CourseManager::get_emails_of_tutors_to_course($courseId);
1846
                if (!empty($mail)) {
1847
                    $teachers_parsed = [];
1848
                    foreach ($mail as $value) {
1849
                        foreach ($value as $email => $name) {
1850
                            $teachers_parsed[] = Display::encrypted_mailto_link($email, $name);
1851
                        }
1852
                    }
1853
                    $label = get_lang('Teacher');
1854
                    if (count($mail) > 1) {
1855
                        $label = get_lang('Teachers');
1856
                    }
1857
                    $teacher_data .= $label.' : '.array_to_string($teachers_parsed, CourseManager::USER_SEPARATOR);
1858
                }
1859
                $this->assign('teachers', $teacher_data);
1860
            }
1861
        }
1862
    }
1863
1864
    /**
1865
     * Set administrator variables.
1866
     */
1867
    private function setAdministratorParams()
1868
    {
1869
        $_admin = [
1870
            'email' => api_get_setting('emailAdministrator'),
1871
            'surname' => api_get_setting('administratorSurname'),
1872
            'name' => api_get_setting('administratorName'),
1873
            'telephone' => api_get_setting('administratorTelephone'),
1874
        ];
1875
1876
        $this->assign('_admin', $_admin);
1877
    }
1878
1879
    /**
1880
     * Manage specific HTTP headers security.
1881
     */
1882
    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...
1883
    {
1884
        // Implementation of HTTP headers security, as suggested and checked
1885
        // by https://securityheaders.io/
1886
        // Enable these settings in configuration.php to use them on your site
1887
        // Strict-Transport-Security
1888
        $setting = api_get_configuration_value('security_strict_transport');
1889
        if (!empty($setting)) {
1890
            header('Strict-Transport-Security: '.$setting);
1891
        }
1892
        // Content-Security-Policy
1893
        $setting = api_get_configuration_value('security_content_policy');
1894
        if (!empty($setting)) {
1895
            header('Content-Security-Policy: '.$setting);
1896
        }
1897
        $setting = api_get_configuration_value('security_content_policy_report_only');
1898
        if (!empty($setting)) {
1899
            header('Content-Security-Policy-Report-Only: '.$setting);
1900
        }
1901
        // Public-Key-Pins
1902
        $setting = api_get_configuration_value('security_public_key_pins');
1903
        if (!empty($setting)) {
1904
            header('Public-Key-Pins: '.$setting);
1905
        }
1906
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1907
        if (!empty($setting)) {
1908
            header('Public-Key-Pins-Report-Only: '.$setting);
1909
        }
1910
        // X-Frame-Options
1911
        $setting = api_get_configuration_value('security_x_frame_options');
1912
        if (!empty($setting)) {
1913
            header('X-Frame-Options: '.$setting);
1914
        }
1915
        // X-XSS-Protection
1916
        $setting = api_get_configuration_value('security_xss_protection');
1917
        if (!empty($setting)) {
1918
            header('X-XSS-Protection: '.$setting);
1919
        }
1920
        // X-Content-Type-Options
1921
        $setting = api_get_configuration_value('security_x_content_type_options');
1922
        if (!empty($setting)) {
1923
            header('X-Content-Type-Options: '.$setting);
1924
        }
1925
        // Referrer-Policy
1926
        $setting = api_get_configuration_value('security_referrer_policy');
1927
        if (!empty($setting)) {
1928
            header('Referrer-Policy: '.$setting);
1929
        }
1930
        // end of HTTP headers security block
1931
    }
1932
1933
    /**
1934
     * Assign favicon to the 'favico' template variable.
1935
     *
1936
     * @return bool Always return true because there is always at least one correct favicon.ico
1937
     */
1938
    private function assignFavIcon()
1939
    {
1940
        // Default root chamilo favicon
1941
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1942
1943
        //Added to verify if in the current Chamilo Theme exist a favicon
1944
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1945
1946
        //If exist pick the current chamilo theme favicon
1947
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1948
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1949
        }
1950
1951
        if (api_is_multiple_url_enabled()) {
1952
            $access_url_id = api_get_current_access_url_id();
1953
            if ($access_url_id != -1) {
1954
                $url_info = api_get_access_url($access_url_id);
1955
                $url = api_remove_trailing_slash(
1956
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1957
                );
1958
                $clean_url = api_replace_dangerous_char($url);
1959
                $clean_url = str_replace('/', '-', $clean_url);
1960
                $clean_url .= '/';
1961
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1962
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1963
                //we create the new dir for the new sites
1964
                if (is_file($icon_real_homep.'favicon.ico')) {
1965
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1966
                }
1967
            }
1968
        }
1969
1970
        $this->assign('favico', $favico);
1971
1972
        return true;
1973
    }
1974
1975
    /**
1976
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1977
     *
1978
     * @return bool Always return true (even if empty string)
1979
     */
1980
    private function assignAccessibilityBlock()
1981
    {
1982
        $resize = '';
1983
        if (api_get_setting('accessibility_font_resize') == 'true') {
1984
            $resize .= '<div class="resize_font">';
1985
            $resize .= '<div class="btn-group">';
1986
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1987
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1988
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1989
            $resize .= '</div>';
1990
            $resize .= '</div>';
1991
        }
1992
        $this->assign('accessibility', $resize);
1993
1994
        return true;
1995
    }
1996
1997
    /**
1998
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1999
     *
2000
     * @return bool Always return true (even if empty string)
2001
     */
2002
    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...
2003
    {
2004
        $socialMeta = '';
2005
        $metaTitle = api_get_setting('meta_title');
2006
        if (!empty($metaTitle)) {
2007
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
2008
            $metaSite = api_get_setting('meta_twitter_site');
2009
            if (!empty($metaSite)) {
2010
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
2011
                $metaCreator = api_get_setting('meta_twitter_creator');
2012
                if (!empty($metaCreator)) {
2013
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
2014
                }
2015
            }
2016
2017
            // The user badge page emits its own meta tags, so if this is
2018
            // enabled, ignore the global ones
2019
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
2020
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
2021
2022
            if (!$userId && !$skillId) {
2023
                // no combination of user and skill ID has been defined,
2024
                // so print the normal or course-specific OpenGraph meta tags
2025
                // Check for a course ID
2026
                $courseId = api_get_course_int_id();
2027
                // Check session ID from session/id/about (see .htaccess)
2028
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
2029
2030
                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...
2031
                    // If we are inside a course (even if within a session), publish info about the course
2032
                    $course = api_get_course_entity($courseId);
2033
                    // @TODO: support right-to-left in title
2034
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
2035
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
2036
2037
                    $metaDescription = api_get_setting('meta_description');
2038
                    if (!empty($course->getDescription())) {
2039
                        $socialMeta .= '<meta property="og:description" content="'.$course->getDescription().'" />'."\n";
2040
                    } elseif (!empty($metaDescription)) {
2041
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
2042
                    }
2043
2044
                    $picture = CourseManager::getPicturePath($course, true);
2045
                    if (!empty($picture)) {
2046
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
2047
                    } else {
2048
                        $socialMeta .= $this->getMetaPortalImagePath();
2049
                    }
2050
                } elseif ($sessionId !== 0) {
2051
                    // If we are on a session "about" screen, publish info about the session
2052
                    $em = Database::getManager();
2053
                    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
2054
2055
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
2056
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."session/{$session->getId()}/about/".'" />'."\n";
2057
2058
                    $sessionValues = new ExtraFieldValue('session');
2059
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
2060
                    $sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
2061
2062
                    if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
2063
                        $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
2064
                        $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
2065
                    } else {
2066
                        $socialMeta .= $this->getMetaPortalImagePath();
2067
                    }
2068
                } else {
2069
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
2070
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
2071
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
2072
2073
                    $metaDescription = api_get_setting('meta_description');
2074
                    if (!empty($metaDescription)) {
2075
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
2076
                    }
2077
                    $socialMeta .= $this->getMetaPortalImagePath();
2078
                }
2079
            }
2080
        }
2081
2082
        $this->assign('social_meta', $socialMeta);
2083
2084
        return true;
2085
    }
2086
2087
    /**
2088
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
2089
     *
2090
     * @return string The meta image HTML tag, or empty
2091
     */
2092
    private function getMetaPortalImagePath()
2093
    {
2094
        // Load portal meta image if defined
2095
        $metaImage = api_get_setting('meta_image_path');
2096
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
2097
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
2098
        $portalImageMeta = '';
2099
        if (!empty($metaImage)) {
2100
            if (is_file($metaImageSysPath)) {
2101
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
2102
            }
2103
        } else {
2104
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
2105
            if (!empty($logo)) {
2106
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
2107
            }
2108
        }
2109
2110
        return $portalImageMeta;
2111
    }
2112
}
2113