Passed
Push — master ( f437d8...92f70a )
by Julito
10:14
created

Template::format_date()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
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
     * Return the item's url key:.
128
     *
129
     *      c_id=xx&id=xx
130
     *
131
     * @param object $item
132
     *
133
     * @return string
134
     */
135
    public static function key($item)
136
    {
137
        $id = isset($item->id) ? $item->id : null;
138
        $c_id = isset($item->c_id) ? $item->c_id : null;
139
        $result = '';
140
        if ($c_id) {
141
            $result = "c_id=$c_id";
142
        }
143
        if ($id) {
144
            if ($result) {
145
                $result .= "&amp;id=$id";
146
            } else {
147
                $result .= "&amp;id=$id";
148
            }
149
        }
150
151
        return $result;
152
    }
153
154
    /**
155
     * @param string $helpInput
156
     */
157
    public function setHelp($helpInput = null)
158
    {
159
        if (!empty($helpInput)) {
160
            $help = $helpInput;
161
        } else {
162
            $help = $this->help;
163
        }
164
165
        $content = '';
166
        if (api_get_setting('enable_help_link') == 'true') {
167
            if (!empty($help)) {
168
                $help = Security::remove_XSS($help);
169
                $content = '<div class="help">';
170
                $content .= Display::url(
171
                    Display::return_icon('help.png', get_lang('Help'), null, ICON_SIZE_LARGE),
172
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
173
                    [
174
                        'class' => 'ajax',
175
                        'data-title' => get_lang('Help'),
176
                    ]
177
                );
178
                $content .= '</div>';
179
            }
180
        }
181
        $this->assign('help_content', $content);
182
    }
183
184
    /**
185
     * Use template system to parse the actions menu.
186
     *
187
     * @todo finish it!
188
     */
189
    public function set_actions($actions)
190
    {
191
        $action_string = '';
192
        if (!empty($actions)) {
193
            foreach ($actions as $action) {
194
                $action_string .= $action;
195
            }
196
        }
197
        $this->assign('actions', $actions);
198
    }
199
200
    /**
201
     * Render the template.
202
     *
203
     * @param string $template           The template path
204
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
205
     */
206
    public function display($template)
207
    {
208
        $template = str_replace('tpl', 'html.twig', $template);
209
        $templateFile = api_get_path(SYS_PATH).'main/template/'.$template;
210
211
        $this->loadLegacyParams();
212
213
        if (!file_exists($templateFile)) {
214
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
215
            echo $e->getMessage();
216
            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...
217
        }
218
219
        $this->returnResponse($this->params, $template);
220
    }
221
222
    /**
223
     * @param string $template
224
     *
225
     * @throws \Twig\Error\Error
226
     */
227
    public function displayTemplate($template)
228
    {
229
        $this->loadLegacyParams();
230
        $this->returnResponse($this->params, $template);
231
    }
232
233
    /**
234
     * Shortcut to display a 1 col layout (index.php).
235
     * */
236
    public function display_one_col_template()
237
    {
238
        $this->loadLegacyParams();
239
        $template = '@ChamiloTheme/Layout/layout_one_col.html.twig';
240
        $this->returnResponse($this->params, $template);
241
    }
242
243
    /**
244
     * Displays an empty template.
245
     */
246
    public function display_blank_template()
247
    {
248
        $this->loadLegacyParams();
249
        $template = '@ChamiloTheme/Layout/blank.html.twig';
250
        $this->returnResponse($this->params, $template);
251
    }
252
253
    /**
254
     * Displays an empty template.
255
     */
256
    public function displayBlankTemplateNoHeader()
257
    {
258
        $this->loadLegacyParams();
259
        $template = '@ChamiloTheme/Layout/blank_no_header.html.twig';
260
        $this->returnResponse($this->params, $template);
261
    }
262
263
    /**
264
     * Displays an empty template.
265
     */
266
    public function display_no_layout_template()
267
    {
268
        $this->loadLegacyParams();
269
        $template = '@ChamiloTheme/Layout/no_layout.html.twig';
270
        $this->returnResponse($this->params, $template);
271
    }
272
273
    /**
274
     * Displays an empty template.
275
     */
276
    public function displaySkillLayout()
277
    {
278
        $this->loadLegacyParams();
279
        $template = '@ChamiloTheme/Layout/skill_layout.html.twig';
280
        $this->returnResponse($this->params, $template);
281
    }
282
283
    /**
284
     * return true if toolbar has to be displayed for user.
285
     *
286
     * @return bool
287
     */
288
    public static function isToolBarDisplayedForUser()
289
    {
290
        //Toolbar
291
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
292
        $show_toolbar = false;
293
294
        switch ($show_admin_toolbar) {
295
            case 'do_not_show':
296
                break;
297
            case 'show_to_admin':
298
                if (api_is_platform_admin()) {
299
                    $show_toolbar = true;
300
                }
301
                break;
302
            case 'show_to_admin_and_teachers':
303
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
304
                    $show_toolbar = true;
305
                }
306
                break;
307
            case 'show_to_all':
308
                $show_toolbar = true;
309
                break;
310
        }
311
312
        return $show_toolbar;
313
    }
314
315
    /**
316
     * Sets the header visibility.
317
     *
318
     * @param bool true if we show the header
319
     */
320
    public function set_header($status)
321
    {
322
        $this->show_header = $status;
323
        $this->assign('show_header', $status);
324
325
        $show_toolbar = 0;
326
        if (self::isToolBarDisplayedForUser()) {
327
            $show_toolbar = 1;
328
        }
329
330
        $this->assign('show_toolbar', $show_toolbar);
331
332
        //Only if course is available
333
        $courseToolBar = '';
334
        $show_course_navigation_menu = '';
335
        if (!empty($this->course_id) && $this->user_is_logged_in) {
336
            if (api_get_setting('show_toolshortcuts') !== 'false') {
337
                // Course toolbar
338
                $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

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

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