Passed
Push — master ( 75577f...fa8cb2 )
by Julito
10:11
created

Template::set_plugin_region()   B

Complexity

Conditions 9
Paths 3

Size

Total Lines 36
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 21
nc 3
nop 1
dl 0
loc 36
rs 8.0555
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_configuration_value('default_template');
121
        if (!empty($defaultStyle)) {
122
            $this->templateFolder = $defaultStyle;
0 ignored issues
show
Documentation Bug introduced by
It seems like $defaultStyle can also be of type boolean. However, the property $templateFolder is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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, $clearFlashMessages = true)
0 ignored issues
show
Unused Code introduced by
The parameter $clearFlashMessages is not used and could be removed. ( Ignorable by Annotation )

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

240
    public function display($template, /** @scrutinizer ignore-unused */ $clearFlashMessages = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

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

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