Completed
Push — master ( 33dc2b...283fc9 )
by Julito
24:27 queued 11:46
created

Template::returnResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 6
rs 9.4285
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,
68
        $show_footer = true,
69
        $show_learnpath = false,
70
        $hide_global_chat = false,
71
        $load_plugins = true,
72
        $sendHeaders = true,
73
        $responseCode = 0
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
        ];
96
97
        $urlId = api_get_current_access_url_id();
98
99
        $cache_folder = api_get_path(SYS_ARCHIVE_PATH).'twig/'.$urlId.'/';
100
101
        if (!is_dir($cache_folder)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
102
            //mkdir($cache_folder, api_get_permissions_for_new_directories(), true);
103
        }
104
105
        $loader = new Twig_Loader_Filesystem($template_paths);
106
107
        $isTestMode = api_get_setting('server_type') === 'test';
108
109
        //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options
110
        if ($isTestMode) {
111
            $options = [
112
                //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder
113
                'autoescape' => false,
114
                'debug' => true,
115
                'auto_reload' => true,
116
                'optimizations' => 0,
117
                // turn on optimizations with -1
118
                'strict_variables' => false,
119
                //If set to false, Twig will silently ignore invalid variables
120
            ];
121
        } else {
122
            $options = [
123
                'cache' => $cache_folder,
124
                //path to the cache folder
125
                'autoescape' => false,
126
                'debug' => false,
127
                'auto_reload' => false,
128
                'optimizations' => -1,
129
                // turn on optimizations with -1
130
                'strict_variables' => false,
131
                //If set to false, Twig will silently ignore invalid variables
132
            ];
133
        }
134
135
        $this->twig = new Twig_Environment($loader, $options);
136
137
        if ($isTestMode) {
138
            $this->twig->addExtension(new Twig_Extension_Debug());
139
        }
140
141
        // Twig filters setup
142
        $filters = [
143
            'get_plugin_lang',
144
            'get_lang',
145
            'api_get_path',
146
            'api_get_local_time',
147
            'api_convert_and_format_date',
148
            'api_is_allowed_to_edit',
149
            'api_get_user_info',
150
            'api_get_configuration_value',
151
            'api_get_setting',
152
            [
153
                'name' => 'return_message',
154
                'callable' => 'Display::return_message_and_translate',
155
            ],
156
            [
157
                'name' => 'display_page_header',
158
                'callable' => 'Display::page_header_and_translate',
159
            ],
160
            [
161
                'name' => 'display_page_subheader',
162
                'callable' => 'Display::page_subheader_and_translate',
163
            ],
164
            [
165
                'name' => 'icon',
166
                'callable' => 'Template::get_icon_path',
167
            ],
168
            [
169
                'name' => 'img',
170
                'callable' => 'Template::get_image',
171
            ],
172
            [
173
                'name' => 'format_date',
174
                'callable' => 'Template::format_date',
175
            ],
176
            [
177
                'name' => 'get_template',
178
                'callable' => 'Template::findTemplateFilePath',
179
            ],
180
        ];
181
182
        foreach ($filters as $filter) {
183
            if (is_array($filter)) {
184
                $this->twig->addFilter(new Twig_SimpleFilter($filter['name'], $filter['callable']));
185
            } else {
186
                $this->twig->addFilter(new Twig_SimpleFilter($filter, $filter));
187
            }
188
        }
189
190
        $functions = [
191
            ['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
192
            ['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
193
        ];
194
195
        foreach ($functions as $function) {
196
            $this->twig->addFunction(new Twig_SimpleFunction($function['name'], $function['callable']));
197
        }
198
199
        // Setting system variables
200
        $this->set_system_parameters();
201
202
        // Setting user variables
203
        $this->set_user_parameters();
204
205
        // Setting course variables
206
        $this->set_course_parameters();
207
208
        // Setting administrator variables
209
        $this->setAdministratorParams();
210
        //$this->setCSSEditor();
211
212
        // Header and footer are showed by default
213
        $this->set_footer($show_footer);
214
        $this->set_header($show_header);
215
216
        $this->set_header_parameters($sendHeaders);
217
        $this->set_footer_parameters();
218
219
        $defaultStyle = api_get_configuration_value('default_template');
220
        if (!empty($defaultStyle)) {
221
            $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...
222
        }
223
224
        $this->assign('template', $this->templateFolder);
225
        $this->assign('locale', api_get_language_isocode());
226
        $this->assign('login_class', null);
227
228
        $allow = api_get_configuration_value('show_language_selector_in_menu');
229
        if ($allow) {
230
            $this->assign('language_form', api_display_language_form());
231
        }
232
233
        // Chamilo plugins
234
        if ($this->show_header) {
235
            if ($this->load_plugins) {
236
                $this->plugin = new AppPlugin();
237
238
                //1. Showing installed plugins in regions
239
                $pluginRegions = $this->plugin->get_plugin_regions();
240
                foreach ($pluginRegions as $region) {
241
                    $this->set_plugin_region($region);
242
                }
243
244
                //2. Loading the course plugin info
245
                global $course_plugin;
246
                if (isset($course_plugin) && !empty($course_plugin) && !empty($this->course_id)) {
247
                    //Load plugin get_langs
248
                    $this->plugin->load_plugin_lang_variables($course_plugin);
249
                }
250
            }
251
        }
252
    }
253
254
    /**
255
     * @param string $image
256
     * @param int    $size
257
     *
258
     * @return string
259
     */
260
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
261
    {
262
        return Display::return_icon($image, '', [], $size, false, true);
263
    }
264
265
    /**
266
     * @param string $image
267
     * @param int    $size
268
     * @param string $name
269
     *
270
     * @return string
271
     */
272
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
273
    {
274
        return Display::return_icon($image, $name, [], $size);
275
    }
276
277
    /**
278
     * @param string $timestamp
279
     * @param string $format
280
     *
281
     * @return string
282
     */
283
    public static function format_date($timestamp, $format = null)
284
    {
285
        return api_format_date($timestamp, $format);
286
    }
287
288
    /**
289
     * Return the item's url key:.
290
     *
291
     *      c_id=xx&id=xx
292
     *
293
     * @param object $item
294
     *
295
     * @return string
296
     */
297
    public static function key($item)
298
    {
299
        $id = isset($item->id) ? $item->id : null;
300
        $c_id = isset($item->c_id) ? $item->c_id : null;
301
        $result = '';
302
        if ($c_id) {
303
            $result = "c_id=$c_id";
304
        }
305
        if ($id) {
306
            if ($result) {
307
                $result .= "&amp;id=$id";
308
            } else {
309
                $result .= "&amp;id=$id";
310
            }
311
        }
312
313
        return $result;
314
    }
315
316
    /**
317
     * @param string $helpInput
318
     */
319
    public function setHelp($helpInput = null)
320
    {
321
        if (!empty($helpInput)) {
322
            $help = $helpInput;
323
        } else {
324
            $help = $this->help;
325
        }
326
327
        $content = '';
328
        if (api_get_setting('enable_help_link') == 'true') {
329
            if (!empty($help)) {
330
                $help = Security::remove_XSS($help);
331
                $content = '<div class="help">';
332
                $content .= Display::url(
333
                    Display::return_icon('help.large.png', get_lang('Help')),
334
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
335
                    [
336
                        'class' => 'ajax',
337
                        'data-title' => get_lang('Help'),
338
                    ]
339
                );
340
                $content .= '</div>';
341
            }
342
        }
343
        $this->assign('help_content', $content);
344
    }
345
346
    /**
347
     * Use template system to parse the actions menu.
348
     *
349
     * @todo finish it!
350
     */
351
    public function set_actions($actions)
352
    {
353
        $action_string = '';
354
        if (!empty($actions)) {
355
            foreach ($actions as $action) {
356
                $action_string .= $action;
357
            }
358
        }
359
        $this->assign('actions', $actions);
360
    }
361
362
    /**
363
     * Render the template.
364
     *
365
     * @param string $template           The template path
366
     * @param bool   $clearFlashMessages Clear the $_SESSION variables for flash messages
367
     */
368
    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

368
    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...
369
    {
370
        $template = str_replace('tpl', 'html.twig', $template);
371
        $templateFile = api_get_path(SYS_PATH).'main/template/'.$template;
372
373
        // Set legacy breadcrumb
374
        global $interbreadcrumb;
375
        $this->params['legacy_breadcrumb'] = $interbreadcrumb;
376
377
        if (!file_exists($templateFile)) {
378
            $e = new \Gaufrette\Exception\FileNotFound($templateFile);
379
            echo $e->getMessage();
380
            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...
381
        }
382
383
        $this->returnResponse($this->params, $template);
384
    }
385
386
    /**
387
     * @param array $params
388
     * @param string $template
389
     *
390
     * @throws \Twig\Error\Error
391
     */
392
    public function returnResponse($params, $template)
393
    {
394
        $response = new Response();
395
        $content = Container::getTemplating()->render($template, $params);
396
        $response->setContent($content);
397
        $response->send();
398
    }
399
400
    /**
401
     * Shortcut to display a 1 col layout (index.php).
402
     * */
403
    public function display_one_col_template()
404
    {
405
        $template = '@ChamiloTheme/Layout/layout_one_col.html.twig';
406
        $this->returnResponse($this->params, $template);
407
    }
408
409
    /**
410
     * Shortcut to display a 2 col layout (userportal.php).
411
     */
412
    public function display_two_col_template()
413
    {
414
        $template = '@ChamiloTheme/Layout/layout_two_col.html.twig';
415
        $this->returnResponse($this->params, $template);
416
    }
417
418
    /**
419
     * Displays an empty template.
420
     */
421
    public function display_blank_template()
422
    {
423
        $tpl = $this->get_template('layout/blank.tpl');
424
        $this->display($tpl);
425
    }
426
427
    /**
428
     * Displays an empty template.
429
     */
430
    public function displayBlankTemplateNoHeader()
431
    {
432
        $tpl = $this->get_template('layout/blank_no_header.tpl');
433
        $this->display($tpl);
434
    }
435
436
    /**
437
     * Displays an empty template.
438
     */
439
    public function display_no_layout_template()
440
    {
441
        $tpl = $this->get_template('layout/no_layout.tpl');
442
        $this->display($tpl);
443
    }
444
445
    /**
446
     * Sets the footer visibility.
447
     *
448
     * @param bool true if we show the footer
449
     */
450
    public function set_footer($status)
451
    {
452
        $this->show_footer = $status;
453
        $this->assign('show_footer', $status);
454
    }
455
456
    /**
457
     * return true if toolbar has to be displayed for user.
458
     *
459
     * @return bool
460
     */
461
    public static function isToolBarDisplayedForUser()
462
    {
463
        //Toolbar
464
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
465
        $show_toolbar = false;
466
467
        switch ($show_admin_toolbar) {
468
            case 'do_not_show':
469
                break;
470
            case 'show_to_admin':
471
                if (api_is_platform_admin()) {
472
                    $show_toolbar = true;
473
                }
474
                break;
475
            case 'show_to_admin_and_teachers':
476
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
477
                    $show_toolbar = true;
478
                }
479
                break;
480
            case 'show_to_all':
481
                $show_toolbar = true;
482
                break;
483
        }
484
485
        return $show_toolbar;
486
    }
487
488
    /**
489
     * Sets the header visibility.
490
     *
491
     * @param bool true if we show the header
492
     */
493
    public function set_header($status)
494
    {
495
        $this->show_header = $status;
496
        $this->assign('show_header', $status);
497
498
        $show_toolbar = 0;
499
500
        if (self::isToolBarDisplayedForUser()) {
501
            $show_toolbar = 1;
502
        }
503
504
        $this->assign('show_toolbar', $show_toolbar);
505
506
        //Only if course is available
507
        $show_course_shortcut = null;
508
        $show_course_navigation_menu = null;
509
510
        if (!empty($this->course_id) && $this->user_is_logged_in) {
511
            if (api_get_setting('show_toolshortcuts') != 'false') {
512
                //Course toolbar
513
                $show_course_shortcut = CourseHome::show_navigation_tool_shortcuts();
514
            }
515
            if (api_get_setting('show_navigation_menu') != 'false') {
516
                //Course toolbar
517
                $show_course_navigation_menu = CourseHome::show_navigation_menu();
518
            }
519
        }
520
        $this->assign('show_course_shortcut', $show_course_shortcut);
521
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
522
    }
523
524
    /**
525
     * Returns the sub-folder and filename for the given tpl file.
526
     * If template not found in overrides/ or custom template folder, the
527
     * default template will be used.
528
     *
529
     * @param string $name
530
     *
531
     * @return string
532
     */
533
    public function get_template($name)
534
    {
535
        // Check if the tpl file is present in the main/template/overrides/ dir
536
        // Overrides is a special directory meant for temporary template
537
        // customization. It must be taken into account before anything else
538
        $file = api_get_path(SYS_CODE_PATH).'template/overrides/'.$name;
539
        if (is_readable($file)) {
540
            return 'overrides/'.$name;
541
        }
542
        // If a template folder has been manually defined, search for the right
543
        // file, and if not found, go for the same file in the default template
544
        if ($this->templateFolder != 'default') {
545
            // Avoid missing template error, use the default file.
546
            $file = api_get_path(SYS_CODE_PATH).'template/'.$this->templateFolder.'/'.$name;
547
            if (!file_exists($file)) {
548
                return 'default/'.$name;
549
            }
550
        }
551
        $name = str_replace('tpl', 'html.twig', $name);
552
553
        return $this->templateFolder.'/'.$name;
554
    }
555
556
    /**
557
     * Get CSS themes sub-directory.
558
     *
559
     * @param string $theme
560
     *
561
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
562
     */
563
    public static function getThemeDir($theme)
564
    {
565
        $themeDir = 'themes/'.$theme.'/';
566
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
567
        if (!empty($virtualTheme)) {
568
            $virtualThemeList = api_get_themes(true);
569
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
570
            if ($isVirtualTheme) {
571
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
572
            }
573
        }
574
575
        return $themeDir;
576
    }
577
578
    /**
579
     * Set system parameters from api_get_configuration into _s array for use in TPLs
580
     * Also fills the _p array from getWebPaths().
581
     *
582
     * @uses \self::getWebPaths()
583
     */
584
    public function set_system_parameters()
585
    {
586
        $this->theme = api_get_visual_theme();
587
        if (!empty($this->preview_theme)) {
588
            $this->theme = $this->preview_theme;
589
        }
590
591
        $this->assign('theme', $this->theme);
592
593
        $this->themeDir = self::getThemeDir($this->theme);
594
595
        // Setting app paths/URLs
596
        $this->assign('_p', $this->getWebPaths());
597
598
        // Here we can add system parameters that can be use in any template
599
        $_s = [
600
            'software_name' => api_get_configuration_value('software_name'),
601
            'system_version' => api_get_configuration_value('system_version'),
602
            'site_name' => api_get_setting('siteName'),
603
            'institution' => api_get_setting('Institution'),
604
            'date' => api_format_date('now', DATE_FORMAT_LONG),
605
            'timezone' => api_get_timezone(),
606
            'gamification_mode' => api_get_setting('gamification_mode'),
607
        ];
608
        $this->assign('_s', $_s);
609
    }
610
611
    /**
612
     * Set legacy twig globals in order to be hook in the LegacyListener.php.
613
     *
614
     * @return array
615
     */
616
    public static function getGlobals()
617
    {
618
        $_p = [
619
            'web' => api_get_path(WEB_PATH),
620
            'web_relative' => api_get_path(REL_PATH),
621
            'web_course' => api_get_path(WEB_COURSE_PATH),
622
            'web_main' => api_get_path(WEB_CODE_PATH),
623
            'web_css' => api_get_path(WEB_CSS_PATH),
624
            //'web_css_theme' => api_get_path(WEB_CSS_PATH) . 'themes/' . $this->theme . '/',
625
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
626
            'web_img' => api_get_path(WEB_IMG_PATH),
627
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
628
            'web_plugin_asset' => api_get_path(WEB_PLUGIN_ASSET_PATH),
629
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
630
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
631
            'web_self' => api_get_self(),
632
            'web_query_vars' => api_htmlentities($_SERVER['QUERY_STRING']),
633
            'web_self_query_vars' => api_htmlentities($_SERVER['REQUEST_URI']),
634
            'web_cid_query' => api_get_cidreq(),
635
        ];
636
637
        $_s = [
638
            'software_name' => api_get_configuration_value('software_name'),
639
            'system_version' => api_get_configuration_value('system_version'),
640
            'site_name' => api_get_setting('siteName'),
641
            'institution' => api_get_setting('Institution'),
642
            //'date' => api_format_date('now', DATE_FORMAT_LONG),
643
            'date' => '',
644
            'timezone' => '',
645
            //'timezone' => api_get_timezone(),
646
            'gamification_mode' => api_get_setting('gamification_mode'),
647
        ];
648
649
        //$user_info = api_get_user_info();
650
651
        return [
652
            '_p' => $_p,
653
            '_s' => $_s,
654
            //       '_u' => $user_info,
655
            'template' => 'default', // @todo setup template folder in config.yml;
656
        ];
657
    }
658
659
    /**
660
     * Set theme, include mainstream CSS files.
661
     *
662
     * @see setCssCustomFiles() for additional CSS sheets
663
     */
664
    public function setCssFiles()
665
    {
666
        global $disable_js_and_css_files;
667
        $css = [];
668
669
        // Default CSS Bootstrap
670
        $bowerCSSFiles = [
671
            'fontawesome/css/font-awesome.min.css',
672
            'jquery-ui/themes/smoothness/theme.css',
673
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
674
            'mediaelement/build/mediaelementplayer.min.css',
675
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
676
            'bootstrap/dist/css/bootstrap.min.css',
677
            'jquery.scrollbar/jquery.scrollbar.css',
678
            'bootstrap-daterangepicker/daterangepicker.css',
679
            'bootstrap-select/dist/css/bootstrap-select.min.css',
680
            'select2/dist/css/select2.min.css',
681
            'flag-icon-css/css/flag-icon.min.css',
682
        ];
683
684
        $features = api_get_configuration_value('video_features');
685
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen'];
686
687
        if (!empty($features) && isset($features['features'])) {
688
            foreach ($features['features'] as $feature) {
689
                $bowerCSSFiles[] = "mediaelement/plugins/$feature/$feature.css";
690
                $defaultFeatures[] = $feature;
691
            }
692
        }
693
694
        foreach ($bowerCSSFiles as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
695
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
696
        }
697
698
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
699
700
        if (api_is_global_chat_enabled()) {
701
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
702
        }
703
        $css_file_to_string = '';
704
        foreach ($css as $file) {
705
            $css_file_to_string .= api_get_css($file);
706
        }
707
708
        if (!$disable_js_and_css_files) {
709
            $this->assign('css_static_file_to_string', $css_file_to_string);
710
        }
711
712
        $defaultFeatures = implode("','", $defaultFeatures);
713
        $this->assign('video_features', $defaultFeatures);
714
    }
715
716
    /**
717
     * Sets the "styles" menu in ckEditor.
718
     *
719
     * Reads css/themes/xxx/editor.css if exists and shows it in the menu, otherwise it
720
     * will take the default web/editor.css file
721
     */
722
    public function setStyleMenuInCkEditor()
723
    {
724
        $cssEditor = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'editor.css');
725
        if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'editor.css')) {
726
            $cssEditor = api_get_path(WEB_CSS_PATH).$this->themeDir.'editor.css';
727
        }
728
        $this->assign('css_editor', $cssEditor);
729
    }
730
731
    /**
732
     * Prepare custom CSS to be added at the very end of the <head> section.
733
     *
734
     * @see setCssFiles() for the mainstream CSS files
735
     */
736
    public function setCssCustomFiles()
737
    {
738
        global $disable_js_and_css_files;
739
        // chamilo CSS
740
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'../chamilo.css');
741
742
        // Base CSS
743
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.css');
744
        $css = [];
745
        if ($this->show_learnpath) {
746
            $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'scorm.css');
747
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
748
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
749
            }
750
        }
751
752
        //$css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->themeDir.'default.css');
753
        $css_file_to_string = '';
754
        foreach ($css as $file) {
755
            $css_file_to_string .= api_get_css($file);
756
        }
757
758
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
759
        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...
760
            //hack in order to fix the actions buttons
761
            $css_file_to_string .= '<style>
762
                .td_actions a {
763
                    float:left;
764
                    width:100%;
765
                }
766
                .forum_message_left a {
767
                    float:left;
768
                    width:100%;
769
                }
770
                </style>';
771
        }
772
773
        $navigator_info = api_get_navigator();
774
        if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') {
775
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
776
        }
777
778
        if (!$disable_js_and_css_files) {
779
            $this->assign('css_custom_file_to_string', $css_file_to_string);
780
781
            $style_print = '';
782
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
783
                $style_print = api_get_css(
784
                    api_get_cdn_path(api_get_path(WEB_CSS_PATH).$this->theme.'/print.css'),
785
                    'print'
786
                );
787
            }
788
            $this->assign('css_style_print', $style_print);
789
        }
790
791
        // Logo
792
        $logo = return_logo($this->theme);
793
        $this->assign('logo', $logo);
794
        $this->assign('show_media_element', 1);
795
    }
796
797
    /**
798
     * Declare and define the template variable that will be used to load
799
     * javascript libraries in the header.
800
     */
801
    public function set_js_files()
802
    {
803
        global $disable_js_and_css_files, $htmlHeadXtra;
804
        $isoCode = api_get_language_isocode();
805
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
806
807
        if ($isoCode == 'en') {
808
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
809
        }
810
        // JS files
811
        $js_files = [
812
            'chosen/chosen.jquery.min.js',
813
        ];
814
815
        $viewBySession = api_get_setting('my_courses_view_by_session') === 'true';
816
817
        if (api_is_global_chat_enabled() || $viewBySession) {
818
            // Do not include the global chat in LP
819
            if ($this->show_learnpath == false &&
820
                $this->show_footer == 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...
821
                $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...
822
            ) {
823
                $js_files[] = 'chat/js/chat.js';
824
            }
825
        }
826
827
        if (api_get_setting('accessibility_font_resize') == 'true') {
828
            $js_files[] = 'fontresize.js';
829
        }
830
831
        $js_file_to_string = '';
832
        $bowerJsFiles = [
833
            'modernizr/modernizr.js',
834
            'jquery/dist/jquery.min.js',
835
            'bootstrap/dist/js/bootstrap.min.js',
836
            'jquery-ui/jquery-ui.min.js',
837
            'moment/min/moment-with-locales.js',
838
            'bootstrap-daterangepicker/daterangepicker.js',
839
            'jquery-timeago/jquery.timeago.js',
840
            'mediaelement/build/mediaelement-and-player.min.js',
841
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
842
            'image-map-resizer/js/imageMapResizer.min.js',
843
            'jquery.scrollbar/jquery.scrollbar.min.js',
844
            //'readmore-js/readmore.min.js',
845
            'bootstrap-select/dist/js/bootstrap-select.min.js',
846
            $selectLink,
847
            'select2/dist/js/select2.min.js',
848
            "select2/dist/js/i18n/$isoCode.js",
849
        ];
850
851
        $features = api_get_configuration_value('video_features');
852
        if (!empty($features) && isset($features['features'])) {
853
            foreach ($features['features'] as $feature) {
854
                $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js";
855
            }
856
        }
857
858
        if (CHAMILO_LOAD_WYSIWYG == 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...
859
            $bowerJsFiles[] = 'ckeditor/ckeditor.js';
860
        }
861
862
        if (api_get_setting('include_asciimathml_script') == 'true') {
863
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
864
        }
865
866
        if ($isoCode != 'en') {
867
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
868
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
869
        }
870
871
        foreach ($bowerJsFiles as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
872
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
873
        }
874
875
        foreach ($js_files as $file) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
876
            //$js_file_to_string .= api_get_js($file);
877
        }
878
879
        // Loading email_editor js
880
        if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') {
881
            $template = $this->get_template('mail_editor/email_link.js.tpl');
882
            $js_file_to_string .= $this->fetch($template);
883
        }
884
885
        if (!$disable_js_and_css_files) {
886
            $this->assign('js_file_to_string', $js_file_to_string);
887
888
            $extra_headers = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
889
            //Adding jquery ui by default
890
            $extra_headers .= api_get_jquery_ui_js();
891
892
            //$extra_headers = '';
893
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
894
                foreach ($htmlHeadXtra as &$this_html_head) {
895
                    $extra_headers .= $this_html_head."\n";
896
                }
897
            }
898
            $this->assign('extra_headers', $extra_headers);
899
        }
900
    }
901
902
    /**
903
     * Special function to declare last-minute JS libraries which depend on
904
     * other things to be declared first. In particular, it might be useful
905
     * under IE9 with compatibility mode, which for some reason is getting
906
     * upset when a variable is used in a function (even if not used yet)
907
     * when this variable hasn't been defined yet.
908
     */
909
    public function set_js_files_post()
910
    {
911
        global $disable_js_and_css_files;
912
        $js_files = [];
913
        if (api_is_global_chat_enabled()) {
914
            //Do not include the global chat in LP
915
            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...
916
                $js_files[] = 'chat/js/chat.js';
917
            }
918
        }
919
        $js_file_to_string = null;
920
921
        foreach ($js_files as $js_file) {
922
            $js_file_to_string .= api_get_js($js_file);
923
        }
924
        if (!$disable_js_and_css_files) {
925
            $this->assign('js_file_to_string_post', $js_file_to_string);
926
        }
927
    }
928
929
    /**
930
     * @param string $theme
931
     *
932
     * @return string
933
     */
934
    public static function getPortalIcon($theme)
935
    {
936
        // Default root chamilo favicon
937
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
938
939
        // Added to verify if in the current Chamilo Theme exist a favicon
940
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).'/themes/'.$theme.'/images/';
941
942
        //If exist pick the current chamilo theme favicon
943
        if (is_file($favicoThemeUrl.'favicon.ico')) {
944
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).'themes/'.$theme.'/images/favicon.ico" type="image/x-icon" />';
945
        }
946
        if (api_is_multiple_url_enabled()) {
947
            $access_url_id = api_get_current_access_url_id();
948
            if ($access_url_id != -1) {
949
                $url_info = api_get_access_url($access_url_id);
950
                $url = api_remove_trailing_slash(
951
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
952
                );
953
                $clean_url = api_replace_dangerous_char($url);
954
                $clean_url = str_replace('/', '-', $clean_url);
955
                $clean_url .= '/';
956
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
957
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
958
                //we create the new dir for the new sites
959
                if (is_file($icon_real_homep.'favicon.ico')) {
960
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
961
                }
962
            }
963
        }
964
965
        //var_dump(Container::$container->get('router')->generate('main', ['name' => '1']));
966
        //var_dump(api_get_path(WEB_PATH));
967
968
        return $favico;
969
    }
970
971
    /**
972
     * Show header template.
973
     */
974
    public function show_header_template()
975
    {
976
        $tpl = $this->get_template('layout/show_header.tpl');
977
        $this->display($tpl);
978
    }
979
980
    /**
981
     * Show footer template.
982
     */
983
    public function show_footer_template()
984
    {
985
        $tpl = $this->get_template('layout/show_footer.tpl');
986
        $this->display($tpl);
987
    }
988
989
    /**
990
     * Show footer js template.
991
     */
992
    public function show_footer_js_template()
993
    {
994
        $tpl = $this->get_template('layout/footer.js.tpl');
995
        $this->display($tpl);
996
    }
997
998
    /**
999
     * Sets the plugin content in a template variable.
1000
     *
1001
     * @param string $pluginRegion
1002
     */
1003
    public function set_plugin_region($pluginRegion)
1004
    {
1005
        if (!empty($pluginRegion)) {
1006
            $regionContent = $this->plugin->load_region(
1007
                $pluginRegion,
1008
                $this,
1009
                $this->force_plugin_load
1010
            );
1011
1012
            $pluginList = $this->plugin->get_installed_plugins();
1013
            foreach ($pluginList as $plugin_name) {
1014
                // The plugin_info variable is available inside the plugin index
1015
                $pluginInfo = $this->plugin->getPluginInfo($plugin_name);
1016
1017
                if (isset($pluginInfo['is_course_plugin']) && $pluginInfo['is_course_plugin']) {
1018
                    $courseInfo = api_get_course_info();
1019
                    if (!empty($courseInfo)) {
1020
                        if (isset($pluginInfo['obj']) && $pluginInfo['obj'] instanceof Plugin) {
1021
                            /** @var Plugin $plugin */
1022
                            $plugin = $pluginInfo['obj'];
1023
                            $regionContent .= $plugin->renderRegion($pluginRegion);
1024
                        }
1025
                    }
1026
                } else {
1027
                    continue;
1028
                }
1029
            }
1030
1031
            if (!empty($regionContent)) {
1032
                $this->assign('plugin_'.$pluginRegion, $regionContent);
1033
            } else {
1034
                $this->assign('plugin_'.$pluginRegion, null);
1035
            }
1036
        }
1037
1038
        return null;
1039
    }
1040
1041
    /**
1042
     * @param string $template
1043
     *
1044
     * @return string
1045
     */
1046
    public function fetch($template = null)
1047
    {
1048
        $template = $this->twig->loadTemplate($template);
1049
1050
        return $template->render($this->params);
1051
    }
1052
1053
    /**
1054
     * @param string $variable
1055
     * @param mixed  $value
1056
     */
1057
    public function assign($variable, $value = '')
1058
    {
1059
        $this->params[$variable] = $value;
1060
    }
1061
1062
    /**
1063
     * Adds a body class for login pages.
1064
     */
1065
    public function setLoginBodyClass()
1066
    {
1067
        $this->assign('login_class', 'section-login');
1068
    }
1069
1070
    /**
1071
     * The theme that will be used if the database is not working.
1072
     *
1073
     * @return string
1074
     */
1075
    public static function getThemeFallback()
1076
    {
1077
        $theme = api_get_configuration_value('theme_fallback');
1078
        if (empty($theme)) {
1079
            $theme = 'chamilo';
1080
        }
1081
1082
        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...
1083
    }
1084
1085
    /**
1086
     * @param bool|true $setLoginForm
1087
     */
1088
    public function setLoginForm($setLoginForm = true)
1089
    {
1090
        global $loginFailed;
1091
        $userId = api_get_user_id();
1092
        if (!($userId) || api_is_anonymous($userId)) {
1093
            // Only display if the user isn't logged in.
1094
            $this->assign(
1095
                'login_language_form',
1096
                api_display_language_form(true, true)
1097
            );
1098
            if ($setLoginForm) {
1099
                $this->assign('login_form', $this->displayLoginForm());
1100
1101
                if ($loginFailed) {
1102
                    $this->assign('login_failed', $this::handleLoginFailed());
0 ignored issues
show
Bug Best Practice introduced by
The method Template::handleLoginFailed() is not static, but was called statically. ( Ignorable by Annotation )

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

1102
                    $this->assign('login_failed', $this::/** @scrutinizer ignore-call */ handleLoginFailed());
Loading history...
1103
                }
1104
            }
1105
        }
1106
    }
1107
1108
    /**
1109
     * @return string
1110
     */
1111
    public function handleLoginFailed()
1112
    {
1113
        $message = get_lang('InvalidId');
1114
1115
        if (!isset($_GET['error'])) {
1116
            if (api_is_self_registration_allowed()) {
1117
                $message = get_lang('InvalidForSelfRegistration');
1118
            }
1119
        } else {
1120
            switch ($_GET['error']) {
1121
                case '':
1122
                    if (api_is_self_registration_allowed()) {
1123
                        $message = get_lang('InvalidForSelfRegistration');
1124
                    }
1125
                    break;
1126
                case 'account_expired':
1127
                    $message = get_lang('AccountExpired');
1128
                    break;
1129
                case 'account_inactive':
1130
                    $message = get_lang('AccountInactive');
1131
1132
                    if (api_get_setting('allow_registration') === 'confirmation') {
1133
                        $message = get_lang('AccountNotConfirmed').PHP_EOL;
1134
                        $message .= Display::url(
1135
                            get_lang('ReSendConfirmationMail'),
1136
                            api_get_path(WEB_PATH).'main/auth/resend_confirmation_mail.php',
1137
                            ['class' => 'alert-link']
1138
                        );
1139
                    }
1140
                    break;
1141
                case 'user_password_incorrect':
1142
                    $message = get_lang('InvalidId');
1143
                    break;
1144
                case 'access_url_inactive':
1145
                    $message = get_lang('AccountURLInactive');
1146
                    break;
1147
                case 'wrong_captcha':
1148
                    $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
1149
                    break;
1150
                case 'blocked_by_captcha':
1151
                    $message = get_lang('AccountBlockedByCaptcha');
1152
                    break;
1153
                case 'multiple_connection_not_allowed':
1154
                    $message = get_lang('MultipleConnectionsAreNotAllow');
1155
                    break;
1156
                case 'unrecognize_sso_origin':
1157
                    //$message = get_lang('SSOError');
1158
                    break;
1159
            }
1160
        }
1161
1162
        return Display::return_message($message, 'error', false);
1163
    }
1164
1165
    /**
1166
     * @return string
1167
     */
1168
    public function displayLoginForm()
1169
    {
1170
        $form = new FormValidator(
1171
            'form-login',
1172
            'POST',
1173
            api_get_path(WEB_PUBLIC_PATH).'login_check',
1174
            null,
1175
            null,
1176
            FormValidator::LAYOUT_BOX_NO_LABEL
1177
        );
1178
        $params = [
1179
            'id' => '_username',
1180
            'autofocus' => 'autofocus',
1181
            'icon' => 'user fa-fw',
1182
            'placeholder' => get_lang('UserName'),
1183
        ];
1184
        $browserAutoCapitalize = false;
1185
        // Avoid showing the autocapitalize option if the browser doesn't
1186
        // support it: this attribute is against the HTML5 standard
1187
        if (api_browser_support('autocapitalize')) {
1188
            $browserAutoCapitalize = false;
1189
            $params['autocapitalize'] = 'none';
1190
        }
1191
        $form->addText(
1192
            '_username',
1193
            get_lang('UserName'),
1194
            true,
1195
            $params
1196
        );
1197
        $params = [
1198
            'id' => '_password',
1199
            'icon' => 'lock fa-fw',
1200
            'placeholder' => get_lang('Pass'),
1201
        ];
1202
        if ($browserAutoCapitalize) {
1203
            $params['autocapitalize'] = 'none';
1204
        }
1205
        $form->addElement(
1206
            'password',
1207
            '_password',
1208
            get_lang('Pass'),
1209
            $params
1210
        );
1211
1212
        $token = Chamilo\CoreBundle\Framework\Container::$container->get('security.csrf.token_manager')->getToken('authenticate');
1213
        $form->addHidden('_csrf_token', $token->getValue());
1214
1215
        // Captcha
1216
        $captcha = api_get_setting('allow_captcha');
1217
        $allowCaptcha = $captcha === 'true';
1218
1219
        if ($allowCaptcha) {
1220
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
1221
            if ($useCaptcha) {
1222
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1223
                $options = [
1224
                    'width' => 250,
1225
                    'height' => 90,
1226
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1227
                    'sessionVar' => basename(__FILE__, '.php'),
1228
                    'imageOptions' => [
1229
                        'font_size' => 20,
1230
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1231
                        'font_file' => 'OpenSans-Regular.ttf',
1232
                        //'output' => 'gif'
1233
                    ],
1234
                ];
1235
1236
                // Minimum options using all defaults (including defaults for Image_Text):
1237
                //$options = array('callback' => 'qfcaptcha_image.php');
1238
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
1239
                $form->addHtml(get_lang('ClickOnTheImageForANewOne'));
1240
1241
                $form->addElement(
1242
                    'text',
1243
                    'captcha',
1244
                    get_lang('EnterTheLettersYouSee')
1245
                );
1246
                $form->addRule(
1247
                    'captcha',
1248
                    get_lang('EnterTheCharactersYouReadInTheImage'),
1249
                    'required',
1250
                    null,
1251
                    'client'
1252
                );
1253
                $form->addRule(
1254
                    'captcha',
1255
                    get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1256
                    'CAPTCHA',
1257
                    $captcha_question
1258
                );
1259
            }
1260
        }
1261
1262
        $form->addButton(
1263
            'submitAuth',
1264
            get_lang('LoginEnter'),
1265
            null,
1266
            'primary',
1267
            null,
1268
            'btn-block'
1269
        );
1270
1271
        $html = $form->returnForm();
1272
        if (api_get_setting('openid_authentication') == 'true') {
1273
            include_once api_get_path(SYS_CODE_PATH).'auth/openid/login.php';
1274
            $html .= '<div>'.openid_form().'</div>';
0 ignored issues
show
Bug introduced by
The function openid_form was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1274
            $html .= '<div>'./** @scrutinizer ignore-call */ openid_form().'</div>';
Loading history...
1275
        }
1276
1277
        return $html;
1278
    }
1279
1280
    /**
1281
     * Returns the tutors names for the current course in session
1282
     * Function to use in Twig templates.
1283
     *
1284
     * @return string
1285
     */
1286
    public static function returnTutorsNames()
1287
    {
1288
        $em = Database::getManager();
1289
        $tutors = $em
1290
            ->createQuery('
1291
                SELECT u FROM ChamiloUserBundle:User u
1292
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
1293
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
1294
            ')
1295
            ->setParameters([
1296
                'teacher_status' => SessionRelCourseRelUser::STATUS_COURSE_COACH,
1297
                'session' => api_get_session_id(),
1298
                'course' => api_get_course_int_id(),
1299
            ])
1300
            ->getResult();
1301
1302
        $names = [];
1303
1304
        /** @var User $tutor */
1305
        foreach ($tutors as $tutor) {
1306
            $names[] = $tutor->getCompleteName();
1307
        }
1308
1309
        return implode(CourseManager::USER_SEPARATOR, $names);
1310
    }
1311
1312
    /*s
1313
     * Returns the teachers name for the current course
1314
     * Function to use in Twig templates
1315
     * @return string
1316
     */
1317
    public static function returnTeachersNames()
1318
    {
1319
        $em = Database::getManager();
1320
        $teachers = $em
1321
            ->createQuery('
1322
                SELECT u FROM ChamiloUserBundle:User u
1323
                INNER JOIN ChamiloCoreBundle:CourseRelUser cu WITH u.id = cu.user
1324
                WHERE cu.status = :teacher_status AND cu.course = :course
1325
            ')
1326
            ->setParameters([
1327
                'teacher_status' => User::COURSE_MANAGER,
1328
                'course' => api_get_course_int_id(),
1329
            ])
1330
            ->getResult();
1331
1332
        $names = [];
1333
1334
        /** @var User $teacher */
1335
        foreach ($teachers as $teacher) {
1336
            $names[] = $teacher->getCompleteName();
1337
        }
1338
1339
        return implode(CourseManager::USER_SEPARATOR, $names);
1340
    }
1341
1342
    /**
1343
     * @param int $code
1344
     */
1345
    public function setResponseCode($code)
1346
    {
1347
        $this->responseCode = $code;
1348
    }
1349
1350
    /**
1351
     * @param string $code
1352
     */
1353
    public function getResponseCode()
1354
    {
1355
        return $this->responseCode;
1356
    }
1357
1358
    /**
1359
     * Prepare the _c array for template files. The _c array contains
1360
     * information about the current course.
1361
     */
1362
    private function set_course_parameters()
1363
    {
1364
        //Setting course id
1365
        $course = api_get_course_info();
1366
        if (empty($course)) {
1367
            $this->assign('course_is_set', false);
1368
1369
            return;
1370
        }
1371
        $this->assign('course_is_set', true);
1372
        $this->course_id = $course['id'];
1373
        $_c = [
1374
            'id' => $course['real_id'],
1375
            'code' => $course['code'],
1376
            'title' => $course['name'],
1377
            'visibility' => $course['visibility'],
1378
            'language' => $course['language'],
1379
            'directory' => $course['directory'],
1380
            'session_id' => api_get_session_id(),
1381
            'user_is_teacher' => api_is_course_admin(),
1382
            'student_view' => (!empty($_GET['isStudentView']) && $_GET['isStudentView'] == 'true'),
1383
        ];
1384
        $this->assign('course_code', $course['code']);
1385
        $this->assign('_c', $_c);
1386
    }
1387
1388
    /**
1389
     * Prepare the _u array for template files. The _u array contains
1390
     * information about the current user, as returned by
1391
     * api_get_user_info().
1392
     */
1393
    private function set_user_parameters()
1394
    {
1395
        $user_info = [];
1396
        $user_info['logged'] = 0;
1397
        $this->user_is_logged_in = false;
1398
        if (api_user_is_login()) {
1399
            $user_info = api_get_user_info(api_get_user_id(), true);
1400
            $user_info['logged'] = 1;
1401
1402
            $user_info['is_admin'] = 0;
1403
            if (api_is_platform_admin()) {
1404
                $user_info['is_admin'] = 1;
1405
            }
1406
1407
            $user_info['messages_count'] = MessageManager::getCountNewMessages();
1408
            $this->user_is_logged_in = true;
1409
        }
1410
        // Setting the $_u array that could be use in any template
1411
        $this->assign('_u', $user_info);
1412
    }
1413
1414
    /**
1415
     * Get an array of all the web paths available (e.g. 'web' => 'https://my.chamilo.site/').
1416
     *
1417
     * @return array
1418
     */
1419
    private function getWebPaths()
1420
    {
1421
        return [
1422
            'web' => api_get_path(WEB_PATH),
1423
            'web_url' => api_get_web_url(),
1424
            'web_relative' => api_get_path(REL_PATH),
1425
            'web_course' => api_get_path(WEB_COURSE_PATH),
1426
            'web_main' => api_get_path(WEB_CODE_PATH),
1427
            'web_css' => api_get_path(WEB_CSS_PATH),
1428
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
1429
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
1430
            'web_img' => api_get_path(WEB_IMG_PATH),
1431
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
1432
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
1433
            'web_upload' => api_get_path(WEB_UPLOAD_PATH),
1434
            'web_self' => api_get_self(),
1435
            'web_query_vars' => api_htmlentities($_SERVER['QUERY_STRING']),
1436
            'web_self_query_vars' => api_htmlentities($_SERVER['REQUEST_URI']),
1437
            'web_cid_query' => api_get_cidreq(),
1438
        ];
1439
    }
1440
1441
    /**
1442
     * Set header parameters.
1443
     *
1444
     * @param bool $sendHeaders send headers
1445
     */
1446
    private function set_header_parameters($sendHeaders)
1447
    {
1448
        global $httpHeadXtra, $interbreadcrumb, $language_file, $_configuration, $this_section;
1449
        $_course = api_get_course_info();
1450
        $nameTools = $this->title;
1451
        $navigation = return_navigation_array();
1452
        $this->menu_navigation = $navigation['menu_navigation'];
1453
1454
        $this->assign('system_charset', api_get_system_encoding());
1455
1456
        if (isset($httpHeadXtra) && $httpHeadXtra) {
1457
            foreach ($httpHeadXtra as &$thisHttpHead) {
0 ignored issues
show
Unused Code introduced by
This foreach statement is empty and can be removed.

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
1458
                //header($thisHttpHead);
1459
            }
1460
        }
1461
1462
        $this->assign(
1463
            'online_button',
1464
            Display::return_icon('statusonline.png', null, [], ICON_SIZE_ATOM)
1465
        );
1466
        $this->assign(
1467
            'offline_button',
1468
            Display::return_icon('statusoffline.png', null, [], ICON_SIZE_ATOM)
1469
        );
1470
1471
        // Get language iso-code for this page - ignore errors
1472
        $this->assign('document_language', api_get_language_isocode());
1473
1474
        $course_title = isset($_course['name']) ? $_course['name'] : null;
1475
1476
        $title_list = [];
1477
1478
        $title_list[] = api_get_setting('Institution');
1479
        $title_list[] = api_get_setting('siteName');
1480
1481
        if (!empty($course_title)) {
1482
            $title_list[] = $course_title;
1483
        }
1484
        if ($nameTools != '') {
1485
            $title_list[] = $nameTools;
1486
        }
1487
1488
        $title_string = '';
1489
        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...
1490
            $title_string .= $title_list[$i];
1491
            if (isset($title_list[$i + 1])) {
1492
                $item = trim($title_list[$i + 1]);
1493
                if (!empty($item)) {
1494
                    $title_string .= ' - ';
1495
                }
1496
            }
1497
        }
1498
1499
        $this->assign('title_string', $title_string);
1500
1501
        // Setting the theme and CSS files
1502
        $this->setCssFiles();
1503
        $this->set_js_files();
1504
        $this->setCssCustomFiles();
1505
1506
        $browser = api_browser_support('check_browser');
1507
        if ($browser[0] == 'Internet Explorer' && $browser[1] >= '11') {
1508
            $browser_head = '<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />';
1509
            $this->assign('browser_specific_head', $browser_head);
1510
        }
1511
1512
        // Implementation of prefetch.
1513
        // See http://cdn.chamilo.org/main/img/online.png for details
1514
        $prefetch = '';
1515
        if (!empty($_configuration['cdn_enable'])) {
1516
            $prefetch .= '<meta http-equiv="x-dns-prefetch-control" content="on">';
1517
            foreach ($_configuration['cdn'] as $host => $exts) {
1518
                $prefetch .= '<link rel="dns-prefetch" href="'.$host.'">';
1519
            }
1520
        }
1521
1522
        $this->assign('prefetch', $prefetch);
1523
        $this->assign('text_direction', api_get_text_direction());
1524
        $this->assign('section_name', 'section-'.$this_section);
1525
        $this->assign('favico', $this->getPortalIcon($this->theme));
1526
        $this->setHelp();
1527
1528
        //@todo move this in the template
1529
        $rightFloatMenu = '';
1530
        $iconBug = Display::return_icon(
1531
            'bug.png',
1532
            get_lang('ReportABug'),
1533
            [],
1534
            ICON_SIZE_LARGE
1535
        );
1536
        if (api_get_setting('show_link_bug_notification') == 'true' && $this->user_is_logged_in) {
1537
            $rightFloatMenu = '<div class="report">
1538
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1539
                    '.$iconBug.'
1540
                </a>
1541
		        </div>';
1542
        }
1543
1544
        if (api_get_setting('show_link_ticket_notification') == 'true' && $this->user_is_logged_in) {
1545
            // by default is project_id = 1
1546
            $iconTicket = Display::return_icon(
1547
                'help.png',
1548
                get_lang('Ticket'),
1549
                [],
1550
                ICON_SIZE_LARGE
1551
            );
1552
            $courseInfo = api_get_course_info();
1553
            $courseParams = '';
1554
            if (!empty($courseInfo)) {
1555
                $courseParams = api_get_cidreq();
1556
            }
1557
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id=1&'.$courseParams;
1558
            $rightFloatMenu .= '<div class="help">
1559
		        <a href="'.$url.'" target="_blank">
1560
                    '.$iconTicket.'
1561
                </a>
1562
		    </div>';
1563
        }
1564
1565
        $this->assign('bug_notification', $rightFloatMenu);
1566
1567
        $resize = '';
1568
        if (api_get_setting('accessibility_font_resize') == 'true') {
1569
            $resize .= '<div class="resize_font">';
1570
            $resize .= '<div class="btn-group">';
1571
            $resize .= '<a title="'.get_lang('DecreaseFontSize').'" href="#" class="decrease_font btn btn-default"><em class="fa fa-font"></em></a>';
1572
            $resize .= '<a title="'.get_lang('ResetFontSize').'" href="#" class="reset_font btn btn-default"><em class="fa fa-font"></em></a>';
1573
            $resize .= '<a title="'.get_lang('IncreaseFontSize').'" href="#" class="increase_font btn btn-default"><em class="fa fa-font"></em></a>';
1574
            $resize .= '</div>';
1575
            $resize .= '</div>';
1576
        }
1577
        $this->assign('accessibility', $resize);
1578
1579
        // Preparing values for the menu
1580
1581
        // Logout link
1582
        $hideLogout = api_get_setting('hide_logout_button');
1583
        if ($hideLogout === 'true') {
1584
            $this->assign('logout_link', null);
1585
        } else {
1586
            $this->assign('logout_link', api_get_path(WEB_PATH).'index.php?logout=logout&uid='.api_get_user_id());
1587
        }
1588
1589
        // Profile link
1590
        if (api_get_setting('allow_social_tool') == 'true') {
1591
            $profile_url = api_get_path(WEB_CODE_PATH).'social/home.php';
1592
        } else {
1593
            $profile_url = api_get_path(WEB_CODE_PATH).'auth/profile.php';
1594
        }
1595
1596
        $this->assign('profile_url', $profile_url);
1597
1598
        //Message link
1599
        $message_link = null;
1600
        $message_url = null;
1601
        if (api_get_setting('allow_message_tool') == 'true') {
1602
            $message_url = api_get_path(WEB_CODE_PATH).'messages/inbox.php';
1603
            $message_link = '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.get_lang('Inbox').'</a>';
1604
        }
1605
        $this->assign('message_link', $message_link);
1606
        $this->assign('message_url', $message_url);
1607
1608
        // Certificate Link
1609
1610
        $allow = api_get_configuration_value('hide_my_certificate_link');
1611
        if ($allow === false) {
1612
            $certificateUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
1613
            $certificateLink = Display::url(
1614
                get_lang('MyCertificates'),
1615
                $certificateUrl
1616
            );
1617
            $this->assign('certificate_link', $certificateLink);
1618
            $this->assign('certificate_url', $certificateUrl);
1619
        }
1620
1621
        $institution = api_get_setting('Institution');
1622
        $portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
1623
1624
        $this->assign('portal_name', $portal_name);
1625
1626
        //Menu
1627
        $menu = menuArray();
1628
        $this->assign('menu', $menu);
1629
1630
        $breadcrumb = '';
1631
        // Hide breadcrumb in LP
1632
        if ($this->show_learnpath == false) {
1633
            $breadcrumb = return_breadcrumb(
1634
                $interbreadcrumb,
1635
                $language_file,
1636
                $nameTools
1637
            );
1638
        }
1639
        $this->assign('breadcrumb', $breadcrumb);
1640
1641
        //Extra content
1642
        $extra_header = null;
1643
        if (!api_is_platform_admin()) {
1644
            $extra_header = trim(api_get_setting('header_extra_content'));
1645
        }
1646
        $this->assign('header_extra_content', $extra_header);
1647
1648
        if ($sendHeaders) {
1649
            /*header('Content-Type: text/html; charset='.api_get_system_encoding());
1650
            header(
1651
                'X-Powered-By: '.$_configuration['software_name'].' '.substr($_configuration['system_version'], 0, 1)
1652
            );
1653
            self::addHTTPSecurityHeaders();*/
1654
1655
            $responseCode = $this->getResponseCode();
1656
            if (!empty($responseCode)) {
1657
                switch ($responseCode) {
1658
                    case '404':
1659
                        header("HTTP/1.0 404 Not Found");
1660
                        break;
1661
                }
1662
            }
1663
        }
1664
1665
        $socialMeta = '';
1666
        $metaTitle = api_get_setting('meta_title');
1667
        if (!empty($metaTitle)) {
1668
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1669
            $metaSite = api_get_setting('meta_twitter_site');
1670
            if (!empty($metaSite)) {
1671
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
1672
                $metaCreator = api_get_setting('meta_twitter_creator');
1673
                if (!empty($metaCreator)) {
1674
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
1675
                }
1676
            }
1677
1678
            // The user badge page emits its own meta tags, so if this is
1679
            // enabled, ignore the global ones
1680
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1681
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1682
1683
            if (!$userId && !$skillId) {
1684
                // no combination of user and skill ID has been defined,
1685
                // so print the normal OpenGraph meta tags
1686
                $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1687
                $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1688
1689
                $metaDescription = api_get_setting('meta_description');
1690
                if (!empty($metaDescription)) {
1691
                    $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1692
                }
1693
1694
                $metaImage = api_get_setting('meta_image_path');
1695
                if (!empty($metaImage)) {
1696
                    if (is_file(api_get_path(SYS_PATH).$metaImage)) {
1697
                        $path = api_get_path(WEB_PATH).$metaImage;
1698
                        $socialMeta .= '<meta property="og:image" content="'.$path.'" />'."\n";
1699
                    }
1700
                }
1701
            }
1702
        }
1703
1704
        $this->assign('social_meta', $socialMeta);
1705
    }
1706
1707
    /**
1708
     * Set footer parameters.
1709
     */
1710
    private function set_footer_parameters()
1711
    {
1712
        if (api_get_setting('show_administrator_data') === 'true') {
1713
            $firstName = api_get_setting('administratorName');
1714
            $lastName = api_get_setting('administratorSurname');
1715
1716
            if (!empty($firstName) && !empty($lastName)) {
1717
                $name = api_get_person_name($firstName, $lastName);
1718
            } else {
1719
                $name = $lastName;
1720
                if (empty($lastName)) {
1721
                    $name = $firstName;
1722
                }
1723
            }
1724
1725
            $adminName = '';
1726
            // Administrator name
1727
            if (!empty($name)) {
1728
                $adminName = get_lang('Manager').' : '.
1729
                    Display::encrypted_mailto_link(
1730
                        api_get_setting('emailAdministrator'),
1731
                        $name
1732
                    );
1733
            }
1734
            $this->assign('administrator_name', $adminName);
1735
        }
1736
1737
        // Loading footer extra content
1738
        if (!api_is_platform_admin()) {
1739
            $extra_footer = trim(api_get_setting('footer_extra_content'));
1740
            if (!empty($extra_footer)) {
1741
                $this->assign('footer_extra_content', $extra_footer);
1742
            }
1743
        }
1744
1745
        // Tutor name
1746
        if (api_get_setting('show_tutor_data') == 'true') {
1747
            // Course manager
1748
            $courseId = api_get_course_int_id();
1749
            $id_session = api_get_session_id();
1750
            if (!empty($courseId)) {
1751
                $tutor_data = '';
1752
                if ($id_session != 0) {
1753
                    $coachs_email = CourseManager::get_email_of_tutor_to_session(
1754
                        $id_session,
1755
                        $courseId
1756
                    );
1757
                    $email_link = [];
1758
                    foreach ($coachs_email as $coach) {
1759
                        $email_link[] = Display::encrypted_mailto_link($coach['email'], $coach['complete_name']);
1760
                    }
1761
                    if (count($coachs_email) > 1) {
1762
                        $tutor_data .= get_lang('Coachs').' : ';
1763
                        $tutor_data .= array_to_string($email_link, CourseManager::USER_SEPARATOR);
1764
                    } elseif (count($coachs_email) == 1) {
1765
                        $tutor_data .= get_lang('Coach').' : ';
1766
                        $tutor_data .= array_to_string($email_link, CourseManager::USER_SEPARATOR);
1767
                    } elseif (count($coachs_email) == 0) {
1768
                        $tutor_data .= '';
1769
                    }
1770
                }
1771
                $this->assign('session_teachers', $tutor_data);
1772
            }
1773
        }
1774
1775
        if (api_get_setting('show_teacher_data') == 'true') {
1776
            // course manager
1777
            $courseId = api_get_course_int_id();
1778
            if (!empty($courseId)) {
1779
                $teacher_data = '';
1780
                $mail = CourseManager::get_emails_of_tutors_to_course($courseId);
1781
                if (!empty($mail)) {
1782
                    $teachers_parsed = [];
1783
                    foreach ($mail as $value) {
1784
                        foreach ($value as $email => $name) {
1785
                            $teachers_parsed[] = Display::encrypted_mailto_link($email, $name);
1786
                        }
1787
                    }
1788
                    $label = get_lang('Teacher');
1789
                    if (count($mail) > 1) {
1790
                        $label = get_lang('Teachers');
1791
                    }
1792
                    $teacher_data .= $label.' : '.array_to_string($teachers_parsed, CourseManager::USER_SEPARATOR);
1793
                }
1794
                $this->assign('teachers', $teacher_data);
1795
            }
1796
        }
1797
    }
1798
1799
    /**
1800
     * Set administrator variables.
1801
     */
1802
    private function setAdministratorParams()
1803
    {
1804
        $_admin = [
1805
            'email' => api_get_setting('emailAdministrator'),
1806
            'surname' => api_get_setting('administratorSurname'),
1807
            'name' => api_get_setting('administratorName'),
1808
            'telephone' => api_get_setting('administratorTelephone'),
1809
        ];
1810
1811
        $this->assign('_admin', $_admin);
1812
    }
1813
1814
    /**
1815
     * Manage specific HTTP headers security.
1816
     */
1817
    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...
1818
    {
1819
        // Implementation of HTTP headers security, as suggested and checked
1820
        // by https://securityheaders.io/
1821
        // Enable these settings in configuration.php to use them on your site
1822
        // Strict-Transport-Security
1823
        $setting = api_get_configuration_value('security_strict_transport');
1824
        if (!empty($setting)) {
1825
            header('Strict-Transport-Security: '.$setting);
1826
        }
1827
        // Content-Security-Policy
1828
        $setting = api_get_configuration_value('security_content_policy');
1829
        if (!empty($setting)) {
1830
            header('Content-Security-Policy: '.$setting);
1831
        }
1832
        $setting = api_get_configuration_value('security_content_policy_report_only');
1833
        if (!empty($setting)) {
1834
            header('Content-Security-Policy-Report-Only: '.$setting);
1835
        }
1836
        // Public-Key-Pins
1837
        $setting = api_get_configuration_value('security_public_key_pins');
1838
        if (!empty($setting)) {
1839
            header('Public-Key-Pins: '.$setting);
1840
        }
1841
        $setting = api_get_configuration_value('security_public_key_pins_report_only');
1842
        if (!empty($setting)) {
1843
            header('Public-Key-Pins-Report-Only: '.$setting);
1844
        }
1845
        // X-Frame-Options
1846
        $setting = api_get_configuration_value('security_x_frame_options');
1847
        if (!empty($setting)) {
1848
            header('X-Frame-Options: '.$setting);
1849
        }
1850
        // X-XSS-Protection
1851
        $setting = api_get_configuration_value('security_xss_protection');
1852
        if (!empty($setting)) {
1853
            header('X-XSS-Protection: '.$setting);
1854
        }
1855
        // X-Content-Type-Options
1856
        $setting = api_get_configuration_value('security_x_content_type_options');
1857
        if (!empty($setting)) {
1858
            header('X-Content-Type-Options: '.$setting);
1859
        }
1860
        // Referrer-Policy
1861
        $setting = api_get_configuration_value('security_referrer_policy');
1862
        if (!empty($setting)) {
1863
            header('Referrer-Policy: '.$setting);
1864
        }
1865
        // end of HTTP headers security block
1866
    }
1867
}
1868