Completed
Push — next ( 5f2bc0...cef70f )
by Thomas
25s queued 12s
created

OcSmarty::display()   F

Complexity

Conditions 27
Paths > 20000

Size

Total Lines 222

Duplication

Lines 5
Ratio 2.25 %

Importance

Changes 0
Metric Value
cc 27
nc 2073600
nop 3
dl 5
loc 222
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/***************************************************************************
3
 * for license information see LICENSE.md
4
 *  Inherit Smarty-Class and extend it
5
 ***************************************************************************/
6
7
use Oc\GeoCache\Enum\GeoCacheType;
8
use Oc\Util\CBench;
9
10
require_once __DIR__ . '/../vendor/autoload.php';
11
require_once __DIR__ . '/db.inc.php';
12
require_once __DIR__ . '/logic/labels.inc.php';
13
14
/**
15
 * Class OcSmarty
16
 */
17
class OcSmarty extends Smarty
18
{
19
    public $name = 'sys_nothing';
20
    public $main_template = 'sys_main';
21
    public $bench = null;
22
    public $compile_id = null;
23
    public $cache_id = null;    // This is a smarty caching ID, not a caches.cache_id.
24
    public $title = '';
25
    public $menuitem = null;
26
    public $nowpsearch = false;
27
    public $change_country_inpage = false;
28
29
    // no header, menu or footer
30
    public $popup = false;
31
32
    // show a thin border when using popup
33
    // disable popupmargin to appear fullscreen
34
    public $popupmargin = true;
35
36
    // url to call if login is required
37
    public $target = '';
38
39
    public $header_javascript = [];
40
    public $body_load = [];
41
    public $body_unload = [];
42
43
    /**
44
     * OcSmarty constructor.
45
     */
46
    public function __construct()
47
    {
48
        global $opt;
49
        $this->bench = new CBench();
50
        $this->bench->start();
51
52
        // configuration
53
        $this->template_dir = $opt['stylepath'];
54
        $this->compile_dir = __DIR__ . '/../var/cache2/smarty/compiled/';
55
        $this->cache_dir = __DIR__ . '/../var/cache2/smarty/cache/';
56
        $this->plugins_dir = [
57
            'plugins',
58
            __DIR__ . '/../src/OcLegacy/SmartyPlugins',
59
        ];
60
61
        // disable caching ... if caching is enabled, 1 hour is default
62
        $this->caching = 0;
63
        $this->cache_lifetime = 3600; // default
64
65
        // register additional functions
66
        require_once __DIR__ . '/../src/OcLegacy/SmartyPlugins/block.nocache.php';
67
        $this->register_block('nocache', 'smarty_block_nocache', false);
68
        $this->load_filter('pre', 't');
69
70
        // cache control
71
        if (($opt['debug'] & DEBUG_TEMPLATES) == DEBUG_TEMPLATES) {
72
            $this->force_compile = true;
73
        }
74
75
        // site maintenance
76
        if (($opt['debug'] & DEBUG_OUTOFSERVICE) == DEBUG_OUTOFSERVICE) {
77
            $this->name = 'sys_outofservice';
78
            $this->display();
79
        }
80
81
        /* set login target
82
         */
83
        if (isset($_REQUEST['target'])) {
84
            $this->target = trim($_REQUEST['target']);
85
            if (preg_match('/^https?:/i', $this->target)) {
86
                $this->target = '';
87
            }
88
        } else {
89
            $target = basename($_SERVER['PHP_SELF']) . '?';
90
91
            // REQUEST-Variablen durchlaufen und an target anhaengen
92
            foreach ($_REQUEST as $varname => $varvalue) {
93
                if (in_array($varname, $opt['logic']['targetvars'])) {
94
                    $target .= urlencode($varname) . '=' . urlencode($varvalue) . '&';
95
                }
96
            }
97
98 View Code Duplication
            if (mb_substr($target, -1) == '?' || mb_substr($target, -1) == '&') {
99
                $target = mb_substr($target, 0, -1);
100
            }
101
102
            $this->target = $target;
103
        }
104
    }
105
106
    /* ATTENTION: copied from internal implementation!
107
     * @param string $resource_name
108
     * @param string $compile_id
109
     */
110
    public function compile($resource_name, $compile_id = null): void
111
    {
112
        if (!isset($compile_id)) {
113
            $compile_id = $this->compile_id;
114
        }
115
116
        $this->_compile_id = $compile_id;
117
118
        // load filters that are marked as autoload
119
        if (count($this->autoload_filters)) {
120
            foreach ($this->autoload_filters as $_filter_type => $_filters) {
121
                foreach ($_filters as $_filter) {
122
                    $this->load_filter($_filter_type, $_filter);
123
                }
124
            }
125
        }
126
127
        $_smarty_compile_path = $this->_get_compile_path($resource_name);
128
129
        // if we just need to display the results, don't perform output
130
        // buffering - for speed
131
        $_cache_including = $this->_cache_including;
132
        $this->_cache_including = false;
0 ignored issues
show
Documentation Bug introduced by
The property $_cache_including was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
133
134
        // compile the resource
135
        if (!$this->_is_compiled($resource_name, $_smarty_compile_path)) {
136
            $this->_compile_resource($resource_name, $_smarty_compile_path);
137
        }
138
139
        $this->_cache_including = $_cache_including;
140
    }
141
142
    /**
143
     * @param null|mixed $dummy1
144
     * @param null|mixed $dummy2
145
     * @param null|mixed $dummy3
146
     */
147
    public function display($dummy1 = null, $dummy2 = null, $dummy3 = null): void
148
    {
149
        global $opt, $db, $cookie, $login, $menu, $sqldebugger, $translate, $useragent_msie;
150
        $cookie->close();
151
152
        // if the user is an admin, don't cache the content
153
        if (isset($login)) {
154
            if ($login->admin) {
155
                $this->caching = 0;
156
            }
157
        }
158
159
        //Give Smarty access to the whole options array.
160
        $this->assign('siteSettings', $opt);
161
        $this->assign('GeoCacheTypeEvent', GeoCacheType::EVENT);
162
163
        //Should we remove this whole block since we now have
164
        //access using the siteSettings above?
165
        // assign main template vars
166
        // ... and some of the $opt
167
        $locale = $opt['template']['locale'];
168
169
        $optn = [];
170
        $optn['debug'] = $opt['debug'];
171
        $optn['template']['locales'] = $opt['template']['locales'];
172
        $optn['template']['locale'] = $opt['template']['locale'];
173
        $optn['template']['style'] = $opt['template']['style'];
174
        $optn['template']['country'] = $login->getUserCountry();
0 ignored issues
show
Bug introduced by
The method getUserCountry cannot be called on $login (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
175
        $optn['page']['subtitle1'] = isset($opt['locale'][$locale]['page']['subtitle1']) ? $opt['locale'][$locale]['page']['subtitle1'] : $opt['page']['subtitle1'];
176
        $optn['page']['subtitle2'] = isset($opt['locale'][$locale]['page']['subtitle2']) ? $opt['locale'][$locale]['page']['subtitle2'] : $opt['page']['subtitle2'];
177
        $optn['page']['sitename'] = $opt['page']['sitename'];
178
        $optn['page']['headimagepath'] = $opt['page']['headimagepath'];
179
        $optn['page']['headoverlay'] = $opt['page']['headoverlay'];
180
        $optn['page']['max_logins_per_hour'] = $opt['page']['max_logins_per_hour'];
181
        $optn['page']['absolute_url'] = $opt['page']['absolute_url'];
182
        $optn['page']['absolute_urlpath'] = parse_url($opt['page']['absolute_url'], PHP_URL_PATH);
183
        $optn['page']['absolute_http_url'] = $opt['page']['absolute_http_url'];
184
        $optn['page']['default_absolute_url'] = $opt['page']['default_absolute_url'];
185
        $optn['page']['login_url'] = ($opt['page']['https']['force_login'] ? $opt['page']['absolute_https_url'] : '') . 'login.php';
186
        $optn['page']['target'] = $this->target;
187
        $optn['page']['showdonations'] = $opt['page']['showdonations'];
188
        $optn['page']['title'] = $opt['page']['title'];
189
        $optn['page']['nowpsearch'] = $this->nowpsearch;
190
        $optn['page']['header_javascript'] = $this->header_javascript;
191
        $optn['page']['body_load'] = $this->body_load;
192
        $optn['page']['body_unload'] = $this->body_unload;
193
        $optn['page']['sponsor'] = $opt['page']['sponsor'];
194
        $optn['page']['showsocialmedia'] = $opt['page']['showsocialmedia'];
195
        $optn['page']['main_country'] = $opt['page']['main_country'];
196
        $optn['page']['main_locale'] = $opt['page']['main_locale'];
197
        $optn['page']['meta'] = $opt['page']['meta'];
198
        $optn['page']['teampic_url'] = $opt['page']['teampic_url'];
199
        $optn['page']['teammember_url'] = $opt['page']['teammember_url'];
200
        $optn['template']['title'] = $this->title;
201
        $optn['template']['caching'] = $this->caching;
202
        $optn['template']['popup'] = $this->popup;
203
        $optn['template']['popupmargin'] = $this->popupmargin;
204
        $optn['format'] = $opt['locale'][$opt['template']['locale']]['format'];
205
        $optn['mail'] = $opt['mail'];
206
        $optn['lib'] = $opt['lib'];
207
        $optn['tracking'] = $opt['tracking'];
208
        $optn['geokrety'] = $opt['geokrety'];
209
        $optn['template']['usercountrieslist'] = labels::getLabels('usercountrieslist');
210
        $optn['help']['oconly'] = helppagelink('oconly', 'OConly');
0 ignored issues
show
Unused Code introduced by
The call to helppagelink() has too many arguments starting with 'OConly'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
211
        $optn['msie'] = $useragent_msie;
212
213
        $loginn = [
214
            'username' => '',
215
            'userid' => '',
216
            'admin' => '',
217
        ];
218
219
        if (isset($login)) {
220
            $loginn['username'] = $login->username;
221
            $loginn['userid'] = $login->userid;
222
            $loginn['admin'] = $login->admin;
223
        }
224
225
        // build menu
226
        if ($this->menuitem == null) {
227
            $menu->SetSelectItem(MNU_ROOT);
228
        } else {
229
            $menu->SetSelectItem($this->menuitem);
230
        }
231
232
        $this->assign('topmenu', $menu->getTopMenu());
233
        $this->assign('submenu', $menu->getSubMenu());
234
        $this->assign('breadcrumb', $menu->getBreadcrumb());
235
        $this->assign('menucolor', $menu->getMenuColor());
236
        $this->assign('helplink', helppagelink($this->name));
237
        $this->assign('change_country_inpage', $this->change_country_inpage);
238
239
        if ($this->title == '') {
240
            $optn['template']['title'] = $menu->GetMenuTitle();
241
        }
242
243
        // build address for switching locales and countries
244
        $base_pageadr = $_SERVER['REQUEST_URI'];
245
246
        // workaround for http://redmine.opencaching.de/issues/703
247
        $strange_things_pos = strpos($base_pageadr, '.php/');
248
        if ($strange_things_pos) {
249
            $base_pageadr = substr($base_pageadr, 0, $strange_things_pos + 4);
250
        }
251
        $lpos = strpos($base_pageadr, 'locale=');
252
        if ($this->change_country_inpage) {
253
            if (!$lpos) {
254
                $lpos = strpos($base_pageadr, 'usercountry=');
255
            }
256
            if (!$lpos) {
257
                $lpos = strpos($base_pageadr, 'country=');
258
            }
259
        }
260
        if ($lpos) {
261
            $base_pageadr = substr($base_pageadr, 0, $lpos);
262
        } else {
263
            $urx = explode('#', $base_pageadr);
264
            $base_pageadr = $urx[0];
265
            if (strpos($base_pageadr, '?') == 0) {
266
                $base_pageadr .= '?';
267
            } else {
268
                $base_pageadr .= '&';
269
            }
270
        }
271
        $this->assign('base_pageadr', $base_pageadr);
272
273
        if ($opt['logic']['license']['disclaimer']) {
274 View Code Duplication
            if (isset($opt['locale'][$locale]['page']['license_url'])) {
275
                $lurl = $opt['locale'][$locale]['page']['license_url'];
276
            } else {
277
                $lurl = $opt['locale']['EN']['page']['license_url'];
278
            }
279
280
            if (isset($opt['locale'][$locale]['page']['license'])) {
281
                $ltext = mb_ereg_replace(
282
                    '{site}',
283
                    $opt['page']['sitename'],
284
                    $opt['locale'][$locale]['page']['license']
285
                );
286
            } else {
287
                $ltext = $opt['locale']['EN']['page']['license'];
288
            }
289
290
            $this->assign('license_disclaimer', mb_ereg_replace('%1', $lurl, $ltext));
291
        } else {
292
            $this->assign('license_disclaimer', '');
293
        }
294
295
        $this->assign('opt', $optn);
296
        $this->assign('login', $loginn);
297
298
        if ($db['connected'] == true) {
299
            $this->assign('sys_dbconnected', true);
300
        } else {
301
            $this->assign('sys_dbconnected', false);
302
        }
303
        $this->assign('sys_dbslave', ($db['slave_id'] != -1));
304
305
        if ($this->template_exists($this->name . '.tpl')) {
306
            $this->assign('template', $this->name);
307
        } elseif ($this->name != 'sys_error') {
308
            $this->error(ERROR_TEMPLATE_NOT_FOUND);
309
        }
310
311
        $this->bench->stop();
312
        $this->assign('sys_runtime', $this->bench->diff());
313
314
        $this->assign(
315
            'screen_css_time',
316
            filemtime(__DIR__ . '/../resource2/' . $opt['template']['style'] . '/css/style_screen.css')
317
        );
318
        $this->assign(
319
            'screen_msie_css_time',
320
            filemtime(__DIR__ . '/../resource2/' . $opt['template']['style'] . '/css/style_screen_msie.css')
321
        );
322
        $this->assign(
323
            'print_css_time',
324
            filemtime(__DIR__ . '/../resource2/' . $opt['template']['style'] . '/css/style_print.css')
325
        );
326
327
        // check if the template is compiled
328
        // if not, check if translation works correct
329
        $_smarty_compile_path = $this->_get_compile_path($this->name);
330
        if (!$this->_is_compiled($this->name, $_smarty_compile_path) && $this->name != 'error') {
331
            $internal_lang = $translate->t('INTERNAL_LANG', 'all', 'OcSmarty.class.php', '');
332
            if (($internal_lang != $opt['template']['locale']) && ($internal_lang != 'INTERNAL_LANG')) {
333
                $this->error(ERROR_COMPILATION_FAILED);
334
            }
335
        }
336
337
        if ($this->is_cached() == true) {
338
            $this->assign('sys_cached', true);
339
        } else {
340
            $this->assign('sys_cached', false);
341
        }
342
343
        if ($db['debug'] === true) {
344
            parent::fetch($this->main_template . '.tpl', $this->get_cache_id(), $this->get_compile_id());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (fetch() instead of display()). Are you sure this is correct? If so, you might want to change this to $this->fetch().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
345
346
            $this->clear_all_assign();
347
            $this->main_template = 'sys_sqldebugger';
348
            $this->assign('commands', $sqldebugger->getCommands());
349
            $this->assign('cancel', $sqldebugger->getCancel());
350
            unset($sqldebugger);
351
352
            $this->assign('opt', $optn);
353
            $this->assign('login', $loginn);
354
355
            $this->caching = 0;
356
357
            // unset sqldebugger to allow proper translation of sqldebugger template
358
            $opt['debug'] = $opt['debug'] & ~DEBUG_SQLDEBUGGER;
359
360
            $this->header();
361
            parent::display($this->main_template . '.tpl');
362
        } else {
363
            $this->header();
364
            parent::display($this->main_template . '.tpl', $this->get_cache_id(), $this->get_compile_id());
365
        }
366
367
        exit;
368
    }
369
370
    /**
371
     * show an error dialog
372
     *
373
     * @param int $id
374
     */
375
    public function error($id): void
376
    {
377
        $this->clear_all_assign();
378
        $this->caching = 0;
379
380
        $this->assign('page', $this->name);
381
        $this->assign('id', $id);
382
383
        if ($this->menuitem == null) {
384
            $this->menuitem = MNU_ERROR;
385
        }
386
387
        $args = func_get_args();
388
        unset($args[0]);
389
        for ($i = 1; isset($args[$i]); $i++) {
390
            $this->assign('p' . $i, $args[$i]);
391
        }
392
393
        $this->name = 'error';
394
        $this->display();
395
    }
396
397
    /**
398
     * check if this template is valid
399
     *
400
     * @param null|mixed $dummy1
401
     * @param null|mixed $dummy2
402
     * @param null|mixed $dummy3
403
     * @return bool|false|string
404
     */
405
    public function is_cached($dummy1 = null, $dummy2 = null, $dummy3 = null)
406
    {
407
        global $login;
408
409
        // if the user is an admin, dont cache the content
410
        if (isset($login)) {
411
            if ($login->admin) {
412
                return false;
413
            }
414
        }
415
416
        return parent::is_cached($this->main_template . '.tpl', $this->get_cache_id(), $this->get_compile_id());
417
    }
418
419
    /**
420
     * @return string
421
     */
422
    public function get_cache_id()
423
    {
424
        // $cache_id can be directly supplied from unverified user input (URL params).
425
        // Probably this is no safety or stability issue, but to be sure we restrict
426
        // the ID to a reasonable set of characters:
427
428
        return $this->name . '|' . mb_ereg_replace('/[^A-Za-z0-9_\|\-\.]/', '', $this->cache_id);
429
    }
430
431
    /**
432
     * @return string
433
     */
434
    public function get_compile_id()
435
    {
436
        global $opt;
437
438
        return $opt['template']['style'] . '|' . $opt['template']['locale'] . '|' . $this->compile_id;
439
    }
440
441
    /**
442
     * @param string $page
443
     */
444
    public function redirect($page): void
445
    {
446
        global $cookie, $opt;
447
        $cookie->close();
448
449
        // close db-connection
450
        sql_disconnect();
0 ignored issues
show
Deprecated Code introduced by
The function sql_disconnect() has been deprecated with message: use DBAL Conenction instead. See adminreports.php for an example implementation
disconnect the database

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
451
452
        $this->header();
453
454
        if (strpos($page, "\n") !== false) {
455
            $page = substr($page, 0, strpos($page, "\n"));
456
        }
457
458
        // redirect
459
        if (!preg_match('/^https?:/i', $page)) {
460
            if (substr($page, 0, 1) == '/') {
461
                $page = substr($page, 1);
462
            }
463
            $page = $opt['page']['absolute_url'] . $page;
464
        }
465
466
467
        header('Location: ' . $page);
468
        exit;
469
    }
470
471
    /**
472
     * redirect login function
473
     */
474
    public function redirect_login(): void
475
    {
476
        global $opt;
477
478
        // we cannot redirect the POST-data
479
        if (count($_POST) > 0) {
480
            $this->error(ERROR_LOGIN_REQUIRED);
481
        }
482
483
        // ok ... redirect the get-data
484
        $target = ($opt['page']['https']['force_login'] ? 'https' : $opt['page']['protocol'])
485
            . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
486
        $this->redirect('login.php?target=' . urlencode($target));
487
    }
488
489
    /**
490
     * @param $name
491
     * @param $rs
492
     */
493 View Code Duplication
    public function assign_rs($name, $rs): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
494
    {
495
        $items = [];
496
        while ($r = sql_fetch_assoc($rs)) {
0 ignored issues
show
Deprecated Code introduced by
The function sql_fetch_assoc() has been deprecated with message: use DBAL Conenction instead. See adminreports.php for an example implementation

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
497
            $items[] = $r;
498
        }
499
        $this->assign($name, $items);
500
    }
501
502
    /**
503
     * @param $src
504
     */
505
    public function add_header_javascript($src): void
506
    {
507
        $this->header_javascript[] = $src;
508
    }
509
510
    /**
511
     * @param $script
512
     */
513
    public function add_body_load($script): void
514
    {
515
        $this->body_load[] = $script;
516
    }
517
518
    /**
519
     * @param $script
520
     */
521
    public function add_body_unload($script): void
522
    {
523
        $this->body_unload[] = $script;
524
    }
525
526
    /**
527
     * setting http header
528
     */
529
    public function header(): void
530
    {
531
        global $opt;
532
        global $cookie;
533
534
        if ($opt['gui'] == GUI_HTML) {
535
            // charset setzen
536
            header('Content-type: text/html; charset=utf-8');
537
538
            // HTTP/1.1
539
            header('Cache-Control: no-store, no-cache, must-revalidate');
540
            header('Cache-Control: post-check=0, pre-check=0', false);
541
            // HTTP/1.0
542
            header('Pragma: no-cache');
543
            // Date in the past
544
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
545
            // always modified
546
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
547
548
            // set the cookie
549
            $cookie->header();
550
        }
551
    }
552
553
    /**
554
     * - trim target and strip newlines
555
     * - use sDefault if sTarget is absolute and sDefault!=null
556
     *
557
     * @param $sTarget
558
     * @param null|mixed $sDefault
559
     * @return null|string
560
     */
561
    public function checkTarget($sTarget, $sDefault = null)
562
    {
563
        if (mb_strpos($sTarget, "\n") !== false) {
564
            $sTarget = mb_substr($sTarget, 0, mb_strpos($sTarget, "\n"));
565
        }
566
567
        $sTarget = mb_trim($sTarget);
568
569
        if (mb_strtolower(mb_substr($sTarget, 0, 7)) == 'http://' || $sTarget == '') {
570
            if ($sDefault != null) {
571
                return $sDefault;
572
            }
573
        }
574
575
        return $sTarget;
576
    }
577
578
    public function acceptsAndPurifiesHtmlInput(): void
579
    {
580
        // Prevent false XSS detection of harmless HTML code
581
        // see https://redmine.opencaching.de/issues/1137
582
        // see https://stackoverflow.com/questions/43249998/chrome-err-blocked-by-xss-auditor-details
583
584
        // XSS protection can be safely disabled if user-supplied content cannot inject JavaScript,
585
        // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
586
        // This is ensured by HTMLpurifier in OC code.
587
588
        header('X-XSS-Protection: 0');
589
    }
590
}
591