Completed
Push — master ( 84362a...46e8ea )
by Julito
10:24
created

Template::loadLegacyParams()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
5
use Chamilo\CoreBundle\Framework\Container;
6
use Chamilo\UserBundle\Entity\User;
7
use Symfony\Component\HttpFoundation\Response;
8
9
/**
10
 * Class Template.
11
 *
12
 * @author Julio Montoya <[email protected]>
13
 *
14
 * @todo better organization of the class, methods and variables
15
 */
16
class Template
17
{
18
    /**
19
     * The Template folder name see main/template.
20
     *
21
     * @var string
22
     */
23
    public $templateFolder = 'default';
24
25
    /**
26
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
27
     * This variable is set from the database.
28
     *
29
     * @var string
30
     */
31
    public $theme = '';
32
33
    /**
34
     * @var string
35
     */
36
    public $preview_theme = '';
37
    public $title = null;
38
    public $show_header;
39
    public $show_footer;
40
    public $help;
41
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
42
    public $show_learnpath = false; // This is a learnpath section or not?
43
    public $plugin = null;
44
    public $course_id = null;
45
    public $user_is_logged_in = false;
46
    public $twig = null;
47
48
    /* Loads chamilo plugins */
49
    public $load_plugins = false;
50
    public $params = [];
51
    public $force_plugin_load = false;
52
    public $responseCode = 0;
53
    private $themeDir;
54
55
    /**
56
     * @param string $title
57
     * @param bool   $show_header
58
     * @param bool   $show_footer
59
     * @param bool   $show_learnpath
60
     * @param bool   $hide_global_chat
61
     * @param bool   $load_plugins
62
     * @param int    $responseCode
63
     * @param bool   $sendHeaders      send http headers or not
64
     */
65
    public function __construct(
66
        $title = '',
67
        $show_header = true,
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
     * Load legacy params
236
     */
237
    private function loadLegacyParams()
238
    {
239
        // Set legacy breadcrumb
240
        global $interbreadcrumb;
241
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
242
243
        global $htmlHeadXtra;
244
        $this->params['legacy_javascript'] = $htmlHeadXtra;
245
    }
246
247
    /**
248
     * Render the template.
249
     *
250
     * @param string $template           The template path
251
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
252
     */
253
    public function display($template)
254
    {
255
        $template = str_replace('tpl', 'html.twig', $template);
256
        $templateFile = api_get_path(SYS_PATH).'main/template/'.$template;
257
258
        $this->loadLegacyParams();
259
260
        if (!file_exists($templateFile)) {
261
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
262
            echo $e->getMessage();
263
            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...
264
        }
265
266
        $this->returnResponse($this->params, $template);
267
    }
268
269
    /**
270
     * @param string $template
271
     *
272
     * @throws \Twig\Error\Error
273
     */
274
    public function displayTemplate($template)
275
    {
276
        $this->loadLegacyParams();
277
        $this->returnResponse($this->params, $template);
278
    }
279
280
    /**
281
     * Shortcut to display a 1 col layout (index.php).
282
     * */
283
    public function display_one_col_template()
284
    {
285
        $this->loadLegacyParams();
286
        $template = '@ChamiloTheme/Layout/layout_one_col.html.twig';
287
        $this->returnResponse($this->params, $template);
288
    }
289
290
    /**
291
     * Displays an empty template.
292
     */
293
    public function display_blank_template()
294
    {
295
        $this->loadLegacyParams();
296
        $template = '@ChamiloTheme/Layout/blank.html.twig';
297
        $this->returnResponse($this->params, $template);
298
    }
299
300
    /**
301
     * Displays an empty template.
302
     */
303
    public function displayBlankTemplateNoHeader()
304
    {
305
        $this->loadLegacyParams();
306
        $template = '@ChamiloTheme/Layout/blank_no_header.html.twig';
307
        $this->returnResponse($this->params, $template);
308
    }
309
310
    /**
311
     * Displays an empty template.
312
     */
313
    public function display_no_layout_template()
314
    {
315
        $this->loadLegacyParams();
316
        $template = '@ChamiloTheme/Layout/no_layout.html.twig';
317
        $this->returnResponse($this->params, $template);
318
    }
319
320
    /**
321
     * Displays an empty template.
322
     */
323
    public function displaySkillLayout()
324
    {
325
        $this->loadLegacyParams();
326
        $template = '@ChamiloTheme/Layout/skill_layout.html.twig';
327
        $this->returnResponse($this->params, $template);
328
    }
329
330
    /**
331
     * return true if toolbar has to be displayed for user.
332
     *
333
     * @return bool
334
     */
335
    public static function isToolBarDisplayedForUser()
336
    {
337
        //Toolbar
338
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
339
        $show_toolbar = false;
340
341
        switch ($show_admin_toolbar) {
342
            case 'do_not_show':
343
                break;
344
            case 'show_to_admin':
345
                if (api_is_platform_admin()) {
346
                    $show_toolbar = true;
347
                }
348
                break;
349
            case 'show_to_admin_and_teachers':
350
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
351
                    $show_toolbar = true;
352
                }
353
                break;
354
            case 'show_to_all':
355
                $show_toolbar = true;
356
                break;
357
        }
358
359
        return $show_toolbar;
360
    }
361
362
    /**
363
     * Sets the header visibility.
364
     *
365
     * @param bool true if we show the header
366
     */
367
    public function set_header($status)
368
    {
369
        $this->show_header = $status;
370
        $this->assign('show_header', $status);
371
372
        $show_toolbar = 0;
373
        if (self::isToolBarDisplayedForUser()) {
374
            $show_toolbar = 1;
375
        }
376
377
        $this->assign('show_toolbar', $show_toolbar);
378
379
        //Only if course is available
380
        $courseToolBar = '';
381
        $show_course_navigation_menu = '';
382
        if (!empty($this->course_id) && $this->user_is_logged_in) {
383
            if (api_get_setting('show_toolshortcuts') !== 'false') {
384
                // Course toolbar
385
                $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

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

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