Completed
Push — master ( 88715c...d7c14e )
by Julito
09:34
created

Template::assignAccessibilityBlock()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 0
dl 0
loc 15
rs 9.9
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,
0 ignored issues
show
Unused Code introduced by
The parameter $show_header 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

67
        /** @scrutinizer ignore-unused */ $show_header = 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...
68
        $show_footer = true,
0 ignored issues
show
Unused Code introduced by
The parameter $show_footer 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

68
        /** @scrutinizer ignore-unused */ $show_footer = 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...
69
        $show_learnpath = false,
70
        $hide_global_chat = false,
71
        $load_plugins = true,
72
        $sendHeaders = true,
0 ignored issues
show
Unused Code introduced by
The parameter $sendHeaders 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

72
        /** @scrutinizer ignore-unused */ $sendHeaders = 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...
73
        $responseCode = 0
0 ignored issues
show
Unused Code introduced by
The parameter $responseCode 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

73
        /** @scrutinizer ignore-unused */ $responseCode = 0

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...
74
    ) {
75
        // Page title
76
        $this->title = $title;
77
        $this->show_learnpath = $show_learnpath;
78
        //$this->setResponseCode($responseCode);
79
80
        if (empty($this->show_learnpath)) {
81
            $origin = api_get_origin();
82
            if ($origin === 'learnpath') {
83
                $this->show_learnpath = true;
84
                $show_footer = false;
85
                $show_header = false;
86
            }
87
        }
88
        $this->hide_global_chat = $hide_global_chat;
0 ignored issues
show
Bug Best Practice introduced by
The property hide_global_chat does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
89
        $this->load_plugins = $load_plugins;
90
91
        /*$template_paths = [
92
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
93
            api_get_path(SYS_CODE_PATH).'template', //template folder
94
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
95
            api_get_path(SYS_PATH).'src/ThemeBundle/Resources/views',
96
        ];*/
97
98
        $this->twig = Container::getTwig();
99
100
        // Setting system variables
101
        //$this->set_system_parameters();
102
103
        // Setting user variables
104
        //$this->set_user_parameters();
105
106
        // Setting course variables
107
        //$this->set_course_parameters();
108
109
        // Setting administrator variables
110
        //$this->setAdministratorParams();
111
        //$this->setCSSEditor();
112
113
        // Header and footer are showed by default
114
        //$this->set_footer($show_footer);
115
        //$this->set_header($show_header);
116
117
        //$this->set_header_parameters($sendHeaders);
118
        //$this->set_footer_parameters();
119
120
        $defaultStyle = api_get_setting('display.default_template');
121
        if (!empty($defaultStyle)) {
122
            $this->templateFolder = $defaultStyle;
123
        }
124
    }
125
126
    /**
127
     * @param string $image
128
     * @param int    $size
129
     *
130
     * @return string
131
     */
132
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
133
    {
134
        return Display::return_icon($image, '', [], $size, false, true);
135
    }
136
137
    /**
138
     * @param string $image
139
     * @param int    $size
140
     * @param string $name
141
     *
142
     * @return string
143
     */
144
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
145
    {
146
        return Display::return_icon($image, $name, [], $size);
147
    }
148
149
    /**
150
     * @param string $timestamp
151
     * @param string $format
152
     *
153
     * @return string
154
     */
155
    public static function format_date($timestamp, $format = null)
156
    {
157
        return api_format_date($timestamp, $format);
158
    }
159
160
    /**
161
     * Return the item's url key:.
162
     *
163
     *      c_id=xx&id=xx
164
     *
165
     * @param object $item
166
     *
167
     * @return string
168
     */
169
    public static function key($item)
170
    {
171
        $id = isset($item->id) ? $item->id : null;
172
        $c_id = isset($item->c_id) ? $item->c_id : null;
173
        $result = '';
174
        if ($c_id) {
175
            $result = "c_id=$c_id";
176
        }
177
        if ($id) {
178
            if ($result) {
179
                $result .= "&amp;id=$id";
180
            } else {
181
                $result .= "&amp;id=$id";
182
            }
183
        }
184
185
        return $result;
186
    }
187
188
    /**
189
     * @param string $helpInput
190
     */
191
    public function setHelp($helpInput = null)
192
    {
193
        if (!empty($helpInput)) {
194
            $help = $helpInput;
195
        } else {
196
            $help = $this->help;
197
        }
198
199
        $content = '';
200
        if (api_get_setting('enable_help_link') == 'true') {
201
            if (!empty($help)) {
202
                $help = Security::remove_XSS($help);
203
                $content = '<div class="help">';
204
                $content .= Display::url(
205
                    Display::return_icon('help.png', get_lang('Help'), null, ICON_SIZE_LARGE),
206
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
207
                    [
208
                        'class' => 'ajax',
209
                        'data-title' => get_lang('Help'),
210
                    ]
211
                );
212
                $content .= '</div>';
213
            }
214
        }
215
        $this->assign('help_content', $content);
216
    }
217
218
    /**
219
     * Use template system to parse the actions menu.
220
     *
221
     * @todo finish it!
222
     */
223
    public function set_actions($actions)
224
    {
225
        $action_string = '';
226
        if (!empty($actions)) {
227
            foreach ($actions as $action) {
228
                $action_string .= $action;
229
            }
230
        }
231
        $this->assign('actions', $actions);
232
    }
233
234
    /**
235
     * Render the template.
236
     *
237
     * @param string $template           The template path
238
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
239
     */
240
    public function display($template)
241
    {
242
        $template = str_replace('tpl', 'html.twig', $template);
243
        $templateFile = api_get_path(SYS_PATH).'main/template/'.$template;
244
245
        // Set legacy breadcrumb
246
        global $interbreadcrumb;
247
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
248
249
        if (!file_exists($templateFile)) {
250
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
251
            echo $e->getMessage();
252
            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...
253
        }
254
255
        $this->returnResponse($this->params, $template);
256
    }
257
258
    /**
259
     * @param array  $params
260
     * @param string $template
261
     *
262
     * @throws \Twig\Error\Error
263
     */
264
    public function returnResponse($params, $template)
265
    {
266
        $flash = Display::getFlashToString();
267
        Display::cleanFlashMessages();
268
        $response = new Response();
269
        $params['flash_messages'] = $flash;
270
        $content = Container::getTemplating()->render($template, $params);
271
        $response->setContent($content);
272
        $response->send();
273
    }
274
275
    /**
276
     * @param string $template
277
     *
278
     * @throws \Twig\Error\Error
279
     */
280
    public function displayTemplate($template)
281
    {
282
        global $htmlHeadXtra;
283
        //var_dump($htmlHeadXtra);exit;
284
        $params['legacy_javascript'] = $htmlHeadXtra;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
285
286
        $this->returnResponse($this->params, $template);
287
    }
288
289
    /**
290
     * Shortcut to display a 1 col layout (index.php).
291
     * */
292
    public function display_one_col_template()
293
    {
294
        $template = '@ChamiloTheme/Layout/layout_one_col.html.twig';
295
        $this->returnResponse($this->params, $template);
296
    }
297
298
    /**
299
     * Shortcut to display a 2 col layout (userportal.php).
300
     */
301
    public function display_two_col_template()
302
    {
303
        $template = '@ChamiloTheme/Layout/layout_content.html.twig';
304
        $this->returnResponse($this->params, $template);
305
    }
306
307
    /**
308
     * Displays an empty template.
309
     */
310
    public function display_blank_template()
311
    {
312
        $template = '@ChamiloTheme/Layout/blank.html.twig';
313
        $this->returnResponse($this->params, $template);
314
    }
315
316
    /**
317
     * Displays an empty template.
318
     */
319
    public function displayBlankTemplateNoHeader()
320
    {
321
        $template = '@ChamiloTheme/Layout/blank_no_header.html.twig';
322
        $this->returnResponse($this->params, $template);
323
    }
324
325
    /**
326
     * Displays an empty template.
327
     */
328
    public function display_no_layout_template()
329
    {
330
        $template = '@ChamiloTheme/Layout/no_layout.html.twig';
331
        $this->returnResponse($this->params, $template);
332
    }
333
334
    /**
335
     * Displays an empty template.
336
     */
337
    public function displaySkillLayout()
338
    {
339
        $template = '@ChamiloTheme/Layout/skill_layout.html.twig';
340
        $this->returnResponse($this->params, $template);
341
    }
342
343
    /**
344
     * return true if toolbar has to be displayed for user.
345
     *
346
     * @return bool
347
     */
348
    public static function isToolBarDisplayedForUser()
349
    {
350
        //Toolbar
351
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
352
        $show_toolbar = false;
353
354
        switch ($show_admin_toolbar) {
355
            case 'do_not_show':
356
                break;
357
            case 'show_to_admin':
358
                if (api_is_platform_admin()) {
359
                    $show_toolbar = true;
360
                }
361
                break;
362
            case 'show_to_admin_and_teachers':
363
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
364
                    $show_toolbar = true;
365
                }
366
                break;
367
            case 'show_to_all':
368
                $show_toolbar = true;
369
                break;
370
        }
371
372
        return $show_toolbar;
373
    }
374
375
    /**
376
     * Sets the header visibility.
377
     *
378
     * @param bool true if we show the header
379
     */
380
    public function set_header($status)
381
    {
382
        $this->show_header = $status;
383
        $this->assign('show_header', $status);
384
385
        $show_toolbar = 0;
386
        if (self::isToolBarDisplayedForUser()) {
387
            $show_toolbar = 1;
388
        }
389
390
        $this->assign('show_toolbar', $show_toolbar);
391
392
        //Only if course is available
393
        $courseToolBar = '';
394
        $show_course_navigation_menu = '';
395
        if (!empty($this->course_id) && $this->user_is_logged_in) {
396
            if (api_get_setting('show_toolshortcuts') !== 'false') {
397
                // Course toolbar
398
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();
0 ignored issues
show
Bug introduced by
The method show_navigation_tool_shortcuts() does not exist on CourseHome. Did you maybe mean show_navigation_menu()? ( Ignorable by Annotation )

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

398
                /** @scrutinizer ignore-call */ 
399
                $courseToolBar = CourseHome::show_navigation_tool_shortcuts();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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

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

1343
        /** @scrutinizer ignore-deprecated */ $this->setCssFiles();
Loading history...
1344
        $this->set_js_files();
1345
        $this->setCssCustomFiles();
1346
1347
        $browser = api_browser_support('check_browser');
1348
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1349
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1350
            $this->assign('browser_specific_head', $browser_head);
1351
        }
1352
1353
        // Implementation of prefetch.
1354
        // See http://cdn.chamilo.org/main/img/online.png for details
1355
        $prefetch = '';
1356
        if (!empty($_configuration['cdn_enable'])) {
1357
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1358
            foreach ($_configuration['cdn'] as $host => $exts) {
1359
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1360
            }
1361
        }
1362
1363
        $this->assign('prefetch', $prefetch);
1364
        $this->assign('text_direction', api_get_text_direction());
1365
        $this->assign('section_name', 'section-'.$this_section);
1366
        $this->assignFavIcon(); //Set a 'favico' var for the template
1367
        $this->setHelp();
1368
        $this->assignBugNotification(); //Prepare the 'bug_notification' var for the template
1369
1370
        // Preparing values for the menu
1371
1372
        // Logout link
1373
        $hideLogout = api_get_setting('hide_logout_button');
1374
        if ($hideLogout === 'true') {
1375
            $this->assign('logout_link', null);
1376
        } else {
1377
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1378
        }
1379
1380
        // Profile link
1381
        if (api_get_setting('allow_social_tool') == 'true') {
1382
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1383
        } else {
1384
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1385
        }
1386
1387
        $this->assign('profile_url', $profile_url);
1388
1389
        //Message link
1390
        $message_link = null;
1391
        $message_url = null;
1392
        if (api_get_setting('allow_message_tool') == 'true') {
1393
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1394
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1395
        }
1396
        $this->assign('message_link', $message_link);
1397
        $this->assign('message_url', $message_url);
1398
1399
        $pendingSurveyLink = '';
1400
        $show = api_get_configuration_value('show_pending_survey_in_menu');
1401
        if ($show) {
1402
            $pendingSurveyLink = api_get_path(WEB_CODE_PATH).'survey/pending.php';
1403
        }
1404
        $this->assign('pending_survey_url', $pendingSurveyLink);
1405
1406
        // Certificate Link
1407
        $allow = api_get_configuration_value('certificate.hide_my_certificate_link');
1408
        if ($allow === false) {
1409
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1410
            $certificateLink = Display::url(
1411
                get_lang('MyCertificates'),
1412
                $certificateUrl
1413
            );
1414
            $this->assign('certificate_link', $certificateLink);
1415
            $this->assign('certificate_url', $certificateUrl);
1416
        }
1417
1418
        $institution = api_get_setting('Institution');
1419
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1420
1421
        $this->assign('portal_name', $portal_name);
1422
1423
        //Menu
1424
        //$menu = menuArray();
1425
        //$this->assign('menu', $menu);
1426
1427
        $breadcrumb = '';
1428
        // Hide breadcrumb in LP
1429
        if ($this->show_learnpath == false) {
1430
            $breadcrumb = return_breadcrumb(
1431
                $interbreadcrumb,
1432
                $language_file,
1433
                $nameTools
1434
            );
1435
        }
1436
        $this->assign('breadcrumb', $breadcrumb);
1437
1438
        //Extra content
1439
        $extra_header = null;
1440
        if (!api_is_platform_admin()) {
1441
            $extra_header = trim(api_get_setting('header_extra_content'));
1442
        }
1443
        $this->assign('header_extra_content', $extra_header);
1444
1445
        if ($sendHeaders) {
1446
            /*header('Content-Type: text/html; charset='.api_get_system_encoding());
1447
            header(
1448
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1449
            );
1450
            self::addHTTPSecurityHeaders();*/
1451
1452
            $responseCode = $this->getResponseCode();
1453
            if (!empty($responseCode)) {
1454
                switch ($responseCode) {
1455
                    case '404':
1456
                        header("HTTP/1.0 404 Not Found");
1457
                        break;
1458
                }
1459
            }
1460
        }
1461
1462
        $socialMeta = '';
1463
        $metaTitle = api_get_setting('meta_title');
1464
        if (!empty($metaTitle)) {
1465
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1466
            $metaSite = api_get_setting('meta_twitter_site');
1467
            if (!empty($metaSite)) {
1468
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1469
                $metaCreator = api_get_setting('meta_twitter_creator');
1470
                if (!empty($metaCreator)) {
1471
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1472
                }
1473
            }
1474
1475
            // The user badge page emits its own meta tags, so if this is
1476
            // enabled, ignore the global ones
1477
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1478
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1479
1480
            if (!$userId && !$skillId) {
1481
                // no combination of user and skill ID has been defined,
1482
                // so print the normal OpenGraph meta tags
1483
                $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1484
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1485
1486
                $metaDescription = api_get_setting('meta_description');
1487
                if (!empty($metaDescription)) {
1488
                    $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1489
                }
1490
1491
                $metaImage = api_get_setting('meta_image_path');
1492
                if (!empty($metaImage)) {
1493
                    if (is_file(api_get_path(SYS_PATH).$metaImage)) {
1494
                        $path = api_get_path(WEB_PATH).$metaImage;
1495
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1496
                    }
1497
                }
1498
            }
1499
        }
1500
1501
        $this->assign('social_meta', $socialMeta);
1502
    }
1503
1504
    /**
1505
     * Set footer parameters.
1506
     */
1507
    private function set_footer_parameters()
0 ignored issues
show
Unused Code introduced by
The method set_footer_parameters() 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...
1508
    {
1509
        // Loading footer extra content
1510
        if (!api_is_platform_admin()) {
1511
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1512
            if (!empty($extra_footer)) {
1513
                $this->assign('footer_extra_content', $extra_footer);
1514
            }
1515
        }
1516
1517
        // Tutor name
1518
    }
1519
1520
    /**
1521
     * Manage specific HTTP headers security.
1522
     */
1523
    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...
1524
    {
1525
        // Implementation of HTTP headers security, as suggested and checked
1526
        // by https://securityheaders.io/
1527
        // Enable these settings in configuration.php to use them on your site
1528
        // Strict-Transport-Security
1529
        $setting = api_get_configuration_value('security_strict_transport');
1530
        if (!empty($setting)) {
1531
            header('Strict-Transport-Security: '.$setting);
1532
        }
1533
        // Content-Security-Policy
1534
        $setting = api_get_configuration_value('security_content_policy');
1535
        if (!empty($setting)) {
1536
            header('Content-Security-Policy: '.$setting);
1537
        }
1538
        $setting = api_get_configuration_value('security_content_policy_report_only');
1539
        if (!empty($setting)) {
1540
            header('Content-Security-Policy-Report-Only: '.$setting);
1541
        }
1542
        // Public-Key-Pins
1543
        $setting = api_get_configuration_value('security_public_key_pins');
1544
        if (!empty($setting)) {
1545
            header('Public-Key-Pins: '.$setting);
1546
        }
1547
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1548
        if (!empty($setting)) {
1549
            header('Public-Key-Pins-Report-Only: '.$setting);
1550
        }
1551
        // X-Frame-Options
1552
        $setting = api_get_configuration_value('security_x_frame_options');
1553
        if (!empty($setting)) {
1554
            header('X-Frame-Options: '.$setting);
1555
        }
1556
        // X-XSS-Protection
1557
        $setting = api_get_configuration_value('security_xss_protection');
1558
        if (!empty($setting)) {
1559
            header('X-XSS-Protection: '.$setting);
1560
        }
1561
        // X-Content-Type-Options
1562
        $setting = api_get_configuration_value('security_x_content_type_options');
1563
        if (!empty($setting)) {
1564
            header('X-Content-Type-Options: '.$setting);
1565
        }
1566
        // Referrer-Policy
1567
        $setting = api_get_configuration_value('security_referrer_policy');
1568
        if (!empty($setting)) {
1569
            header('Referrer-Policy: '.$setting);
1570
        }
1571
        // end of HTTP headers security block
1572
    }
1573
1574
    /**
1575
     * Assign favicon to the 'favico' template variable.
1576
     *
1577
     * @return bool Always return true because there is always at least one correct favicon.ico
1578
     */
1579
    private function assignFavIcon()
1580
    {
1581
        // Default root chamilo favicon
1582
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1583
        //Added to verify if in the current Chamilo Theme exist a favicon
1584
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1585
1586
        //If exist pick the current chamilo theme favicon
1587
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1588
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1589
        }
1590
1591
        if (api_is_multiple_url_enabled()) {
1592
            $access_url_id = api_get_current_access_url_id();
1593
            if ($access_url_id != -1) {
1594
                $url_info = api_get_access_url($access_url_id);
1595
                $url = api_remove_trailing_slash(
1596
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1597
                );
1598
                $clean_url = api_replace_dangerous_char($url);
1599
                $clean_url = str_replace('/', '-', $clean_url);
1600
                $clean_url .= '/';
1601
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1602
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1603
                //we create the new dir for the new sites
1604
                if (is_file($icon_real_homep.'favicon.ico')) {
1605
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1606
                }
1607
            }
1608
        }
1609
1610
        $this->assign('favico', $favico);
1611
1612
        return true;
1613
    }
1614
1615
    /**
1616
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1617
     *
1618
     * @return bool Always return true (even if empty string)
1619
     */
1620
    private function assignAccessibilityBlock()
0 ignored issues
show
Unused Code introduced by
The method assignAccessibilityBlock() 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...
1621
    {
1622
        $resize = '';
1623
        if (api_get_setting('accessibility_font_resize') == 'true') {
1624
            $resize .= '<div class="resize_font">';
1625
            $resize .= '<div class="btn-group">';
1626
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1627
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1628
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1629
            $resize .= '</div>';
1630
            $resize .= '</div>';
1631
        }
1632
        $this->assign('accessibility', $resize);
1633
1634
        return true;
1635
    }
1636
1637
    /**
1638
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1639
     *
1640
     * @return bool Always return true (even if empty string)
1641
     */
1642
    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...
1643
    {
1644
        $socialMeta = '';
1645
        $metaTitle = api_get_setting('meta_title');
1646
        if (!empty($metaTitle)) {
1647
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1648
            $metaSite = api_get_setting('meta_twitter_site');
1649
            if (!empty($metaSite)) {
1650
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1651
                $metaCreator = api_get_setting('meta_twitter_creator');
1652
                if (!empty($metaCreator)) {
1653
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1654
                }
1655
            }
1656
1657
            // The user badge page emits its own meta tags, so if this is
1658
            // enabled, ignore the global ones
1659
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1660
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1661
1662
            if (!$userId && !$skillId) {
1663
                // no combination of user and skill ID has been defined,
1664
                // so print the normal or course-specific OpenGraph meta tags
1665
                // Check for a course ID
1666
                $courseId = api_get_course_int_id();
1667
                // Check session ID from session/id/about (see .htaccess)
1668
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1669
1670
                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...
1671
                    // If we are inside a course (even if within a session), publish info about the course
1672
                    $course = api_get_course_entity($courseId);
1673
                    // @TODO: support right-to-left in title
1674
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1675
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1676
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getCode()).'" />'."\n";
1677
1678
                    $metaDescription = api_get_setting('meta_description');
1679
                    if (!empty($course->getDescription())) {
1680
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1681
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1682
                    } elseif (!empty($metaDescription)) {
1683
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1684
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1685
                    }
1686
1687
                    $picture = CourseManager::getPicturePath($course, true);
1688
                    if (!empty($picture)) {
1689
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1690
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
1691
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1692
                    } else {
1693
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1694
                    }
1695
                } elseif ($sessionId !== 0) {
1696
                    // If we are on a session "about" screen, publish info about the session
1697
                    $em = Database::getManager();
1698
                    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
1699
1700
                    $socialMeta .= '<meta property="og:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1701
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1702
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."session/{$session->getId()}/about/".'" />'."\n";
1703
1704
                    $sessionValues = new ExtraFieldValue('session');
1705
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1706
                    $sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1707
1708
                    if (!empty($sessionImage) && is_file($sessionImageSysPath)) {
1709
                        $sessionImagePath = api_get_path(WEB_UPLOAD_PATH).$sessionImage;
1710
                        $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1711
                        $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
1712
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getName().' - '.$metaTitle.'" />'."\n";
1713
                    } else {
1714
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1715
                    }
1716
                } else {
1717
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
1718
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1719
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
1720
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1721
1722
                    $metaDescription = api_get_setting('meta_description');
1723
                    if (!empty($metaDescription)) {
1724
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1725
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1726
                    }
1727
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1728
                }
1729
            }
1730
        }
1731
1732
        $this->assign('social_meta', $socialMeta);
1733
1734
        return true;
1735
    }
1736
1737
    /**
1738
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
1739
     *
1740
     * @param string $imageAlt The alt attribute for the image
1741
     *
1742
     * @return string The meta image HTML tag, or empty
1743
     */
1744
    private function getMetaPortalImagePath($imageAlt = '')
1745
    {
1746
        // Load portal meta image if defined
1747
        $metaImage = api_get_setting('meta_image_path');
1748
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
1749
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
1750
        $portalImageMeta = '';
1751
        if (!empty($metaImage)) {
1752
            if (is_file($metaImageSysPath)) {
1753
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
1754
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
1755
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1756
            }
1757
        } else {
1758
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
1759
            if (!empty($logo)) {
1760
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
1761
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
1762
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1763
            }
1764
        }
1765
1766
        return $portalImageMeta;
1767
    }
1768
}
1769