Passed
Push — master ( c1c3f8...b5db60 )
by Julito
08:30
created

Template::displayTemplate()   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 1
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
     * @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.large.png', get_lang('Help')),
206
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
207
                    [
208
                        'class' => 'ajax',
209
                        'data-title' => get_lang('Help'),
210
                    ]
211
                );
212
                $content .= '</div>';
213
            }
214
        }
215
        $this->assign('help_content', $content);
216
    }
217
218
    /**
219
     * Use template system to parse the actions menu.
220
     *
221
     * @todo finish it!
222
     */
223
    public function set_actions($actions)
224
    {
225
        $action_string = '';
226
        if (!empty($actions)) {
227
            foreach ($actions as $action) {
228
                $action_string .= $action;
229
            }
230
        }
231
        $this->assign('actions', $actions);
232
    }
233
234
    /**
235
     * Render the template.
236
     *
237
     * @param string $template           The template path
238
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
239
     */
240
    public function display($template)
241
    {
242
        $template = str_replace('tpl', 'html.twig', $template);
243
        $templateFile = api_get_path(SYS_PATH).'main/template/'.$template;
244
245
        // Set legacy breadcrumb
246
        global $interbreadcrumb;
247
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
248
249
        if (!file_exists($templateFile)) {
250
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
251
            echo $e->getMessage();
252
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

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

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