Completed
Push — next ( 3cfa04...53c79d )
by Thomas
07:00
created

common.inc.php ➔ tpl_acceptsAndPurifiesHtmlInput()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/****************************************************************************
3
 * For license information see LICENSE.md
4
 *
5
 * sets up all necessary variables and handle template and database-things
6
 * also useful functions
7
 *
8
 * parameter: lang       get/post/cookie   used language
9
 * style      get/post/cookie   used style
10
 ****************************************************************************/
11
12
use Oc\Util\CBench;
13
14
if (isset($opt['rootpath'])) {
15
    $rootpath = $opt['rootpath'];
16
} else {
17
    if (isset($rootpath)) {
18
        $opt['rootpath'] = $rootpath;
19
    } else {
20
        $rootpath = './';
21
        $opt['rootpath'] = $rootpath;
22
    }
23
}
24
25
// we are in HTML-mode ... maybe plain (for CLI scripts)
26
global $interface_output, $bScriptExecution;
27
$interface_output = 'html';
28
29
// set default CSS
30
tpl_set_var('css', 'main.css');
31
32
//detecting errors
33
$error = false;
34
35
if (!isset($rootpath)) {
36
    $rootpath = './';
37
}
38
require_once __DIR__ . '/clicompatbase.inc.php';
39
40
// enforce http or https?
41
if (isset($opt['gui']) && $opt['gui'] == GUI_HTML) {
42
    if ($opt['page']['https']['mode'] == HTTPS_DISABLED) {
43
        if ($opt['page']['https']['active']) {
44
            header('Location: http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']);
0 ignored issues
show
Security Response Splitting introduced by
'Location: http://' . $_...$_SERVER['REQUEST_URI'] can contain request data and is used in response header context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Fetching key REQUEST_URI from $_SERVER
    in htdocs/lib/common.inc.php on line 44

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
45
        }
46
        $opt['page']['force_https_login'] = false;
47 View Code Duplication
    } else {
48
        if ($opt['page']['https']['mode'] == HTTPS_ENFORCED) {
49
            if (!$opt['page']['https']['active']) {
50
                header('Location: https://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']);
0 ignored issues
show
Security Response Splitting introduced by
'Location: https://' . $...$_SERVER['REQUEST_URI'] can contain request data and is used in response header context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Fetching key REQUEST_URI from $_SERVER
    in htdocs/lib/common.inc.php on line 50

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
51
            }
52
            $opt['page']['force_https_login'] = true;
53
        }
54
    }
55
}
56
57
// load domain specific settings
58
load_domain_settings();
59
60
// load HTML specific includes
61
$cookie = new \Oc\Session\SessionDataCookie();
62
63
//by default, use start template
64
if (!isset($tplname)) {
65
    $tplname = 'start';
66
}
67
68
//restore cookievars[]
69
load_cookie_settings();
70
71
//language changed?
72
if (isset($_POST['lang'])) {
73
    $lang = $_POST['lang'];
74
}
75
if (isset($_GET['lang'])) {
76
    $lang = $_GET['lang'];
77
}
78
79
//are there files for this language?
80
if (!file_exists(__DIR__ . '/../lang/' . $lang . '/')) {
81
    die('Critical Error: The specified language does not exist!');
82
}
83
84
//style changed?
85
if (isset($_POST['style'])) {
86
    $style = $_POST['style'];
87
}
88
if (isset($_GET['style'])) {
89
    $style = $_GET['style'];
90
}
91
92
//does the style exist?
93 View Code Duplication
if (!file_exists(__DIR__ . '/../lang/' . $lang . '/' . $style . '/')) {
94
    $style = 'ocstyle';
95
}
96
97 View Code Duplication
if (!file_exists(__DIR__ . '/../lang/' . $lang . '/' . $style . '/')) {
98
    die('Critical Error: The specified style does not exist!');
99
}
100
101
//set up the language path
102
if (!isset($langpath)) {
103
    $langpath = __DIR__ . '/../lang/' . $lang;
104
}
105
106
//set up the style path
107
if (!isset($stylepath)) {
108
    $stylepath = $langpath . '/' . $style;
109
}
110
111
//load gettext translation
112
load_gettext();
113
114
//open a databse connection
115
db_connect();
116
117
require_once __DIR__ . '/auth.inc.php';
118
require_once __DIR__ . '/../lib2/translate.class.php';
119
120
//load language specific strings
121
require_once $langpath . '/expressions.inc.php';
122
123
//set up the defaults for the main template
124
require_once $stylepath . '/varset.inc.php';
125
126
if ($dblink === false) {
127
    //error while connecting to the database
128
    $error = true;
129
130
    //set up error report
131
    tpl_set_var('error_msg', htmlspecialchars(mysql_error(), ENT_COMPAT, 'UTF-8'));
132
    tpl_set_var('tplname', $tplname);
133
    $tplname = 'error';
134
} else {
135
    //user authenification from cookie
136
    auth_user();
137
    if ($usr == false) {
138
        //no user logged in
139
        if (isset($_POST['target'])) {
140
            $target = $_POST['target'];
141
        } elseif (isset($_REQUEST['target'])) {
142
            $target = $_REQUEST['target'];
143
        } elseif (isset($_GET['target'])) {
144
            $target = $_GET['target'];
145
        } else {
146
            $target = '{target}';
147
        }
148
        $sLoggedOut = mb_ereg_replace('{target}', $target, $sLoggedOut);
0 ignored issues
show
Security Code Execution introduced by
$target can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read from $_POST, and $target is assigned in htdocs/lib/common.inc.php on line 140
  1. Read from $_POST, and $target is assigned
    in htdocs/lib/common.inc.php on line 140
  2. Path: Read from $_REQUEST, and $target is assigned in htdocs/lib/common.inc.php on line 142
  1. Read from $_REQUEST, and $target is assigned
    in htdocs/lib/common.inc.php on line 142
  3. Path: Read from $_GET, and $target is assigned in htdocs/lib/common.inc.php on line 144
  1. Read from $_GET, and $target is assigned
    in htdocs/lib/common.inc.php on line 144

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
149
        tpl_set_var('loginbox', $sLoggedOut);
150
        tpl_set_var(
151
            'login_url',
152
            ($opt['page']['https']['force_login'] ? $opt['page']['absolute_https_url'] : '') . 'login.php'
153
        );
154
    } else {
155
        //user logged in
156
        $sTmpString = mb_ereg_replace('{username}', $usr['username'], $sLoggedIn);
157
        tpl_set_var('loginbox', $sTmpString);
158
        unset($sTmpString);
159
    }
160
}
161
162
// are we Ocprop?
163
$ocpropping = isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'Ocprop/') !== false;
164
165
// zeitmessung
166
$bScriptExecution = new CBench;
167
$bScriptExecution->start();
168
169
function load_domain_settings()
170
{
171
    global $opt, $style;
172
173
    $domain = $opt['page']['domain'];
174
175
    if (isset($opt['domain'][$domain]['style'])) {
176
        $style = $opt['domain'][$domain]['style'];
177
    }
178 View Code Duplication
    if (isset($opt['domain'][$domain]['cookiedomain'])) {
179
        $opt['cookie']['domain'] = $opt['domain'][$domain]['cookiedomain'];
180
    }
181
182
    set_common_domain_config($opt);
183
}
184
185
// get the language from a given shortage
186
// on success return the name, otherwise false
187
function db_LanguageFromShort($langCode)
188
{
189
    global $dblink, $locale;
190
191
    //no databse connection?
192
    if ($dblink === false) {
193
        return false;
194
    }
195
196
    //select the right record
197
    $rs = sql(
198
        "SELECT IFNULL(`sys_trans_text`.`text`, `languages`.`name`) AS `text`
199
        FROM `languages`
200
        LEFT JOIN `sys_trans`
201
          ON `languages`.`trans_id`=`sys_trans`.`id`
202
        LEFT JOIN `sys_trans_text`
203
          ON `sys_trans`.`id`=`sys_trans_text`.`trans_id`
204
          AND `sys_trans_text`.`lang`='&1'
205
        WHERE `languages`.`short`='&2'",
206
        $locale,
207
        $langCode
208
    );
209
    if (mysql_num_rows($rs) > 0) {
210
        $record = sql_fetch_array($rs);
211
212
        //return the language
213
        return $record['text'];
214
    } else {
215
        //language not found
216
        return false;
217
    }
218
}
219
220
//get the stored settings and authentification data from the cookie
221
function load_cookie_settings()
222
{
223
    global $cookie, $lang, $style;
224
225
    //speach
226
    if ($cookie->is_set('lang')) {
227
        $lang = $cookie->get('lang');
228
    }
229
230
    //style
231
    if ($cookie->is_set('style')) {
232
        $style = $cookie->get('style');
233
    }
234
}
235
236
//store the cookie vars
237
function write_cookie_settings()
238
{
239
    global $cookie, $lang, $style;
240
241
    //language
242
    $cookie->set('lang', $lang);
243
244
    //style
245
    $cookie->set('style', $style);
246
247
    //send cookie
248
    $cookie->header();
249
}
250
251
//returns the cookie value, otherwise false
252
function get_cookie_setting($name)
253
{
254
    global $cookie;
255
256
    if ($cookie->is_set($name)) {
257
        return $cookie->get($name);
258
    } else {
259
        return false;
260
    }
261
}
262
263
//sets the cookie value
264
function set_cookie_setting($name, $value)
265
{
266
    global $cookie;
267
    $cookie->set($name, $value);
268
}
269
270
//set a template replacement
271
//set no_eval true to prevent this contents from php-parsing.
272
//Important when replacing something that the user has posted
273
//in HTML code and could contain \<\? php-Code \?\>
274
/**
275
 * @param string $name
276
 */
277
function tpl_set_var($name, $value, $no_eval = true)
278
{
279
    global $vars, $no_eval_vars;
280
    $vars[$name] = $value;
281
    $no_eval_vars[$name] = $no_eval;
282
}
283
284
//get a template replacement, otherwise false
285
function tpl_get_var($name)
286
{
287
    global $vars;
288
289
    if (isset($vars[$name])) {
290
        return $vars[$name];
291
    } else {
292
        return false;
293
    }
294
}
295
296
//clear all template vars
297
function tpl_clear_vars()
0 ignored issues
show
Coding Style introduced by
tpl_clear_vars uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
298
{
299
    unset($GLOBALS['vars']);
300
    unset($GLOBALS['no_eval_vars']);
301
}
302
303
/**
304
 * page function replaces {functionsbox} in main template
305
 *
306
 * @param $id
307
 * @param $html_code
308
 */
309
function tpl_set_page_function($id, $html_code)
310
{
311
    global $page_functions;
312
313
    $page_functions[$id] = $html_code;
314
}
315
316
function tpl_unset_page_function($id)
317
{
318
    global $page_functions;
319
320
    unset($page_functions[$id]);
321
}
322
323
function tpl_clear_page_functions()
0 ignored issues
show
Coding Style introduced by
tpl_clear_page_functions uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
324
{
325
    unset($GLOBALS['page_functions']);
326
}
327
328
/**
329
 * see OcSmarty::acceptsAndPurifiesHtmlInput
330
 */
331
function tpl_acceptsAndPurifiesHtmlInput()
332
{
333
    header('X-XSS-Protection: 0');
334
}
335
336
/**
337
 * read the templates and echo it to the user
338
 *
339
 * @param bool $dbDisconnect
340
 */
341
function tpl_BuildTemplate($dbDisconnect = true)
0 ignored issues
show
Coding Style introduced by
tpl_BuildTemplate uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
342
{
343
    global $sql_debug, $sqldbg_cmdNo;
344
345
    if (isset($sql_debug) && $sql_debug) {
346
        if (!isset($sqldbg_cmdNo) || $sqldbg_cmdNo == 0) {
347
            echo 'No SQL commands on this page.';
348
        }
349
        die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function tpl_BuildTemplate() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
350
    }
351
352
    //template handling vars
353
    global $style, $stylepath, $tplname, $vars, $langpath, $locale, $opt, $oc_nodeid, $translate, $usr;
354
    //language specific expression
355
    global $error_pagenotexist;
356
    //only for debbuging
357
    global $b, $bScriptExecution;
358
    // country dropdown
359
    global $tpl_usercountries;
360
361
    tpl_set_var('screen_css_time', filemtime(__DIR__ . '/../resource2/' . $style . '/css/style_screen.css'));
362
    tpl_set_var(
363
        'screen_msie_css_time',
364
        filemtime(__DIR__ . '/../resource2/' . $style . '/css/style_screen_msie.css')
365
    );
366
    tpl_set_var('print_css_time', filemtime(__DIR__ . '/../resource2/' . $style . '/css/style_print.css'));
367
368
    if (isset($bScriptExecution)) {
369
        $bScriptExecution->stop();
370
        tpl_set_var('scripttime', sprintf('%1.3f', $bScriptExecution->diff()));
371
    } else {
372
        tpl_set_var('scripttime', sprintf('%1.3f', 0));
373
    }
374
375
    tpl_set_var('sponsorbottom', $opt['page']['sponsor']['bottom']);
376
377 View Code Duplication
    if (isset($opt['locale'][$locale]['page']['subtitle1'])) {
378
        $opt['page']['subtitle1'] = $opt['locale'][$locale]['page']['subtitle1'];
379
    }
380 View Code Duplication
    if (isset($opt['locale'][$locale]['page']['subtitle2'])) {
381
        $opt['page']['subtitle2'] = $opt['locale'][$locale]['page']['subtitle2'];
382
    }
383
    tpl_set_var('opt_page_subtitle1', $opt['page']['subtitle1']);
384
    tpl_set_var('opt_page_subtitle2', $opt['page']['subtitle2']);
385
    tpl_set_var('opt_page_title', $opt['page']['title']);
386
387
    if ($opt['logic']['license']['disclaimer']) {
388 View Code Duplication
        if (isset($opt['locale'][$locale]['page']['license_url'])) {
389
            $lurl = $opt['locale'][$locale]['page']['license_url'];
390
        } else {
391
            $lurl = $opt['locale']['EN']['page']['license_url'];
392
        }
393
394 View Code Duplication
        if (isset($opt['locale'][$locale]['page']['license'])) {
395
            $ltext = $opt['locale'][$locale]['page']['license'];
396
        } else {
397
            $ltext = $opt['locale']['EN']['page']['license'];
398
        }
399
400
        $ltext = mb_ereg_replace('%1', $lurl, $ltext);
401
        $ltext = mb_ereg_replace('{site}', $opt['page']['sitename'], $ltext);
402
403
        $ld = '<p class="sidebar-maintitle">' . $translate->t('Datalicense', '', '', 0) . '</p>' .
404
            '<div style="margin:20px 0 16px 0; width:100%; text-align:center;">' . $ltext . '</div>';
405
        tpl_set_var('license_disclaimer', $ld);
406
    } else {
407
        tpl_set_var('license_disclaimer', '');
408
    }
409
410
    $bTemplateBuild = new CBench;
411
    $bTemplateBuild->start();
412
413
    //set {functionsbox}
414
    global $page_functions, $functionsbox_start_tag, $functionsbox_middle_tag, $functionsbox_end_tag;
415
416
    if (isset($page_functions)) {
417
        $functionsbox = $functionsbox_start_tag;
418
        foreach ($page_functions as $func) {
419
            if ($functionsbox != $functionsbox_start_tag) {
420
                $functionsbox .= $functionsbox_middle_tag;
421
            }
422
            $functionsbox .= $func;
423
        }
424
        $functionsbox .= $functionsbox_end_tag;
425
426
        tpl_set_var('functionsbox', $functionsbox);
427
    }
428
429
    /* prepare user country selection
430
     */
431
    $tpl_usercountries = [];
432
    $rsUserCountries = sql(
433
        "SELECT `countries_options`.`country`,
434
                        IF(`countries_options`.`nodeId`='&1', 1, IF(`countries_options`.`nodeId`!=0, 2, 3)) AS `group`,
435
                        IFNULL(`sys_trans_text`.`text`, `countries`.`name`) AS `name`
436
                   FROM `countries_options`
437
             INNER JOIN `countries` ON `countries_options`.`country`=`countries`.`short`
438
              LEFT JOIN `sys_trans` ON `countries`.`trans_id`=`sys_trans`.`id`
439
              LEFT JOIN `sys_trans_text` ON `sys_trans`.`id`=`sys_trans_text`.`trans_id` AND `sys_trans_text`.`lang`='&2'
440
                  WHERE `countries_options`.`display`=1
441
               ORDER BY `group` ASC,
442
                        IFNULL(`sys_trans_text`.`text`, `countries`.`name`) ASC",
443
        $oc_nodeid,
444
        $locale
445
    );
446
    while ($rUserCountries = sql_fetch_assoc($rsUserCountries)) {
447
        $tpl_usercountries[] = $rUserCountries;
448
    }
449
    sql_free_result($rsUserCountries);
450
451
    //include language specific expressions, so that they are available in the template code
452
    include $langpath . '/expressions.inc.php';
453
454
    //load main template
455
    tpl_set_var('backgroundimage', '<div id="bg1">&nbsp;</div><div id="bg2">&nbsp;</div>');
456
    tpl_set_var('bodystyle', '');
457
458
    if (isset($_REQUEST['print']) && $_REQUEST['print'] == 'y') {
459
        $sCode = read_file($stylepath . '/main_print.tpl.php');
460
    } else {
461
        if (isset($_REQUEST['popup']) && $_REQUEST['popup'] == 'y') {
462
            $sCode = read_file($stylepath . '/popup.tpl.php');
463
        } else {
464
            $sCode = read_file($stylepath . '/main.tpl.php');
465
        }
466
    }
467
    $sCode = '?>' . $sCode;
468
469
    //does template exist?
470
    if (!file_exists($stylepath . '/' . $tplname . '.tpl.php')) {
471
        //set up the error template
472
        $error = true;
0 ignored issues
show
Unused Code introduced by
$error is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
473
        tpl_set_var('error_msg', htmlspecialchars($error_pagenotexist, ENT_COMPAT, 'UTF-8'));
474
        tpl_set_var('tplname', $tplname);
475
        $tplname = 'error';
476
    }
477
478
    //read the template
479
    $sTemplate = read_file($stylepath . '/' . $tplname . '.tpl.php');
480
    $sCode = mb_ereg_replace('{template}', $sTemplate, $sCode);
481
482
    //process translations
483
    $sCode = tpl_do_translation($sCode);
484
485
    //process the template replacements
486
    $sCode = tpl_do_replace($sCode);
487
488
    // fixing path issue
489
    $sCode = str_replace('lib2/smarty/ocplugins/', 'src/OcLegacy/SmartyPlugins/', $sCode);
490
491
    //store the cookie
492
    write_cookie_settings();
493
494
    //send http-no-caching-header
495
    http_write_no_cache();
496
497
    // write UTF8-Header
498
    header('Content-type: text/html; charset=utf-8');
499
500
    //run the template code
501
    eval($sCode);
0 ignored issues
show
Coding Style introduced by
The function tpl_BuildTemplate() contains an eval expression.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
502
503
    //disconnect the database
504
    if ($dbDisconnect) {
505
        db_disconnect();
506
    }
507
}
508
509
function http_write_no_cache()
510
{
511
    // HTTP/1.1
512
    header('Cache-Control: no-store, no-cache, must-revalidate');
513
    header('Cache-Control: post-check=0, pre-check=0', false);
514
    // HTTP/1.0
515
    header('Pragma: no-cache');
516
    // Date in the past
517
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
518
    // always modified
519
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
520
}
521
522
//redirect to another site to display, i.e. to view a cache after logging
523
/**
524
 * @param string $page
525
 */
526
function tpl_redirect($page)
527
{
528
    global $absolute_server_URI;
529
530
    write_cookie_settings();
531
    http_write_no_cache();
532
533
    if (!preg_match('/^https?:/i', $page)) {
534
        header('Location: ' . $absolute_server_URI . $page);
0 ignored issues
show
Security Response Splitting introduced by
'Location: ' . $absolute_server_URI . $page can contain request data and is used in response header context(s) leading to a potential security vulnerability.

4 paths for user data to reach this point

  1. Path: Read from $_REQUEST, and $cache_id is assigned in htdocs/newdesc.php on line 20
  1. Read from $_REQUEST, and $cache_id is assigned
    in htdocs/newdesc.php on line 20
  2. $cache_id is escaped by urlencode() for all (url-encoded) context(s), and 'editcache.php?cacheid=' . urlencode($cache_id) is passed to tpl_redirect()
    in htdocs/newdesc.php on line 143
  2. Path: Read from $_REQUEST, and $cache_id is assigned in htdocs/removedesc.php on line 16
  1. Read from $_REQUEST, and $cache_id is assigned
    in htdocs/removedesc.php on line 16
  2. $cache_id is escaped by urlencode() for all (url-encoded) context(s), and 'editcache.php?cacheid=' . urlencode($cache_id) is passed to tpl_redirect()
    in htdocs/removedesc.php on line 72
  3. Path: Read from $_REQUEST, and $sessionid is assigned in htdocs/xml/ocxml11.php on line 118
  1. Read from $_REQUEST, and $sessionid is assigned
    in htdocs/xml/ocxml11.php on line 118
  2. $sessionid is passed to outputXmlSessionFile()
    in htdocs/xml/ocxml11.php on line 129
  3. $sessionid is passed to outputXmlFile()
    in htdocs/xml/ocxml11.php on line 1513
  4. $rel_xmlfile is assigned
    in htdocs/xml/ocxml11.php on line 1044
  5. $zip_wwwdir . $rel_xmlfile is passed to tpl_redirect()
    in htdocs/xml/ocxml11.php on line 1049
  4. Path: Read from $_REQUEST, and $filenr is assigned in htdocs/xml/ocxml11.php on line 119
  1. Read from $_REQUEST, and $filenr is assigned
    in htdocs/xml/ocxml11.php on line 119
  2. $filenr is passed to outputXmlSessionFile()
    in htdocs/xml/ocxml11.php on line 129
  3. $filenr is passed to outputXmlFile()
    in htdocs/xml/ocxml11.php on line 1513
  4. $rel_xmlfile is assigned
    in htdocs/xml/ocxml11.php on line 1044
  5. $zip_wwwdir . $rel_xmlfile is passed to tpl_redirect()
    in htdocs/xml/ocxml11.php on line 1049

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
535
    } else {
536
        header('Location: ' . $page);
0 ignored issues
show
Security Response Splitting introduced by
'Location: ' . $page can contain request data and is used in response header context(s) leading to a potential security vulnerability.

4 paths for user data to reach this point

  1. Path: Read from $_REQUEST, and $cache_id is assigned in htdocs/newdesc.php on line 20
  1. Read from $_REQUEST, and $cache_id is assigned
    in htdocs/newdesc.php on line 20
  2. $cache_id is escaped by urlencode() for all (url-encoded) context(s), and 'editcache.php?cacheid=' . urlencode($cache_id) is passed to tpl_redirect()
    in htdocs/newdesc.php on line 143
  2. Path: Read from $_REQUEST, and $cache_id is assigned in htdocs/removedesc.php on line 16
  1. Read from $_REQUEST, and $cache_id is assigned
    in htdocs/removedesc.php on line 16
  2. $cache_id is escaped by urlencode() for all (url-encoded) context(s), and 'editcache.php?cacheid=' . urlencode($cache_id) is passed to tpl_redirect()
    in htdocs/removedesc.php on line 72
  3. Path: Read from $_REQUEST, and $sessionid is assigned in htdocs/xml/ocxml11.php on line 118
  1. Read from $_REQUEST, and $sessionid is assigned
    in htdocs/xml/ocxml11.php on line 118
  2. $sessionid is passed to outputXmlSessionFile()
    in htdocs/xml/ocxml11.php on line 129
  3. $sessionid is passed to outputXmlFile()
    in htdocs/xml/ocxml11.php on line 1513
  4. $rel_xmlfile is assigned
    in htdocs/xml/ocxml11.php on line 1044
  5. $zip_wwwdir . $rel_xmlfile is passed to tpl_redirect()
    in htdocs/xml/ocxml11.php on line 1049
  4. Path: Read from $_REQUEST, and $filenr is assigned in htdocs/xml/ocxml11.php on line 119
  1. Read from $_REQUEST, and $filenr is assigned
    in htdocs/xml/ocxml11.php on line 119
  2. $filenr is passed to outputXmlSessionFile()
    in htdocs/xml/ocxml11.php on line 129
  3. $filenr is passed to outputXmlFile()
    in htdocs/xml/ocxml11.php on line 1513
  4. $rel_xmlfile is assigned
    in htdocs/xml/ocxml11.php on line 1044
  5. $zip_wwwdir . $rel_xmlfile is passed to tpl_redirect()
    in htdocs/xml/ocxml11.php on line 1049

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
537
    }
538
539
    exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function tpl_redirect() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
540
}
541
542
//process the template replacements
543
//no_eval_replace - if true, variables will be replaced that are
544
//                  marked as "no_eval"
545
/**
546
 * @param string $str
547
 * @return string
548
 */
549
function tpl_do_replace($str)
550
{
551
    global $vars, $no_eval_vars;
552
553
    if (is_array($vars)) {
554
        foreach ($vars as $varname => $varvalue) {
555
            if ($no_eval_vars[$varname] == false) {
556
                $str = mb_ereg_replace('{' . $varname . '}', $varvalue, $str);
557
            } else {
558
                $replave_var_name = 'tpl_replace_var_' . $varname;
559
560
                global $$replave_var_name;
561
                $$replave_var_name = $varvalue;
562
563
                //replace using php-echo
564
                $str = mb_ereg_replace(
565
                    '{' . $varname . '}',
566
                    '<?php global $' . $replave_var_name . '; echo $tpl_replace_var_' . $varname . '; ?>',
567
                    $str
568
                );
569
            }
570
        }
571
    }
572
573
    return $str;
574
}
575
576
/**
577
 * @param string $tplnameError
578
 * @param string $msg
579
 */
580
function tpl_errorMsg($tplnameError, $msg)
581
{
582
    global $tplname;
583
584
    $tplname = 'error';
585
    tpl_set_var('error_msg', $msg);
586
    tpl_set_var('tplname', $tplnameError);
587
588
    tpl_BuildTemplate();
589
    exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function tpl_errorMsg() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
590
}
591
592
593
function load_gettext()
0 ignored issues
show
Coding Style introduced by
load_gettext uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
594
{
595
    global $cookie, $opt, $locale;
596
597
    $locale = isset($_REQUEST['locale']) ? $_REQUEST['locale'] : $cookie->get('locale');
598
    if (!isset($opt['locale'][$locale])) {
599
        $locale = $opt['template']['default']['locale'];
600
    }
601
    $opt['template']['locale'] = $locale;
602
603
    $cookie->set('locale', $opt['template']['locale'], $opt['template']['default']['locale']);
604
605
    bindtextdomain('messages', __DIR__ . '/../var/cache2/translate');
606
    set_php_locale();
607
    textdomain('messages');
608
}
609
610
/**
611
 * @param string $sCode
612
 * @return string
613
 */
614
function tpl_do_translation($sCode)
615
{
616
    global $opt, $style, $tplname;
617
618
    $sResultCode = '';
619
    $nCurrentPos = 0;
620
    while ($nCurrentPos < mb_strlen($sCode)) {
621
        $nStartOfHTML = mb_strpos($sCode, '?>', $nCurrentPos);
622
        if ($nStartOfHTML === false) {
623
            $sResultCode .= mb_substr($sCode, $nCurrentPos, mb_strlen($sCode) - $nCurrentPos);
624
            $nCurrentPos = mb_strlen($sCode);
625
        } else {
626
            $nEndOfHTML = mb_strpos($sCode, '<?', $nStartOfHTML);
627
            if ($nEndOfHTML === false) {
628
                $nEndOfHTML = mb_strlen($sCode);
629
            }
630
631
            $sResultCode .= mb_substr($sCode, $nCurrentPos, $nStartOfHTML - $nCurrentPos);
632
            $sHTMLCode = mb_substr($sCode, $nStartOfHTML, $nEndOfHTML - $nStartOfHTML);
633
            $sResultCode .= gettext_do_html($sHTMLCode);
634
635
            $nCurrentPos = $nEndOfHTML;
636
        }
637
    }
638
639
    return $sResultCode;
640
}
641
642
/**
643
 * @param string $sCode
644
 * @return string
645
 */
646
function gettext_do_html($sCode)
647
{
648
    $sResultCode = '';
649
    $nCurrentPos = 0;
650
    while ($nCurrentPos < mb_strlen($sCode)) {
651
        $nStartOf = mb_strpos($sCode, '{' . 't}', $nCurrentPos);
652
        if ($nStartOf === false) {
653
            $sResultCode .= mb_substr($sCode, $nCurrentPos, mb_strlen($sCode) - $nCurrentPos);
654
            $nCurrentPos = mb_strlen($sCode);
655
        } else {
656
            $nEndOf = mb_strpos($sCode, '{/t}', $nStartOf);
657
            if ($nEndOf === false) {
658
                $nEndOf = mb_strlen($sCode);
659
            } else {
660
                $nEndOf += 4;
661
            }
662
663
            $sResultCode .= mb_substr($sCode, $nCurrentPos, $nStartOf - $nCurrentPos);
664
            $sTransString = mb_substr($sCode, $nStartOf + 3, $nEndOf - $nStartOf - 3 - 4);
665
666
            $sResultCode .= t($sTransString);
667
668
            $nCurrentPos = $nEndOf;
669
        }
670
    }
671
672
    return $sResultCode;
673
}
674
675
/**
676
 * @param $str
677
 * @return string
678
 */
679
function t($str)
680
{
681
    global $translate;
682
683
    $str = $translate->t($str, '', basename(__FILE__), __LINE__);
684
    $args = func_get_args();
685
    for ($nIndex = count($args) - 1; $nIndex > 0; $nIndex--) {
686
        $str = str_replace('%' . $nIndex, $args[$nIndex], $str);
687
    }
688
689
    return $str;
690
}
691
692
/**
693
 * @param $text
694
 * @return string
695
 */
696 View Code Duplication
function t_prepare_text($text)
0 ignored issues
show
Duplication introduced by
This function 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...
697
{
698
    $text = mb_ereg_replace("\t", ' ', $text);
699
    $text = mb_ereg_replace("\r", ' ', $text);
700
    $text = mb_ereg_replace("\n", ' ', $text);
701
    while (mb_strpos($text, '  ') !== false) {
702
        $text = mb_ereg_replace('  ', ' ', $text);
703
    }
704
705
    return $text;
706
}
707
708
/**
709
 * @return mixed|null|string
710
 */
711
function getUserCountry()
712
{
713
    global $opt, $cookie, $usr;
714
715
    // language specified in cookie?
716 View Code Duplication
    if ($cookie->is_set('usercountry')) {
717
        $sCountry = $cookie->get('usercountry', null);
718
        if ($sCountry != null) {
719
            return $sCountry;
720
        }
721
    }
722
723
    // user specified a country?
724
    if (isset($usr) && ($usr !== false)) {
725
        $sCountry = sqlValue("SELECT `country` FROM `user` WHERE `user_id`='" . ($usr['userid'] + 0) . "'", null);
726
        if ($sCountry != null) {
727
            return $sCountry;
728
        }
729
    }
730
731
    // default country of this language
732
    //
733
    // disabled: produces unexpected results on multi-domains without translation,
734
    // and will confusingly switch country when switching language  -- following 3.9.2015
735
    //
736
    // if (isset($opt['template']['locale']) && isset($opt['locale'][$opt['template']['locale']]['country']))
0 ignored issues
show
Unused Code Comprehensibility introduced by
90% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
737
    //    return $opt['locale'][$opt['template']['locale']]['country'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
90% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
738
739
    // default country of installation (or domain)
740
    if (isset($opt['template']['default']['country'])) {
741
        return $opt['template']['default']['country'];
742
    }
743
744
    // country could not be determined by the above checks -> return "GB"
745
    return 'GB';
746
}
747
748
/**
749
 * external help embedding
750
 * pay attention to use only ' quotes in $text (escape other ')
751
 *
752
 * see corresponding function in lib2/common.inc.php
753
 * @param $ocPage
754
 * @return string
755
 */
756
function helppagelink($ocPage)
757
{
758
    global $opt, $locale, $translate;
759
760
    $help_locale = $locale;
761
    $rs = sql(
762
        "SELECT `helppage` FROM `helppages` WHERE `ocpage`='&1' AND `language`='&2'",
763
        $ocPage,
764
        $help_locale
765
    );
766
    if (mysql_num_rows($rs) == 0) {
767
        mysql_free_result($rs);
768
        $rs = sql(
769
            "SELECT `helppage` FROM `helppages` WHERE `ocpage`='&1' AND `language`='*'",
770
            $ocPage
771
        );
772
    }
773
    if (mysql_num_rows($rs) == 0) {
774
        mysql_free_result($rs);
775
        $rs = sql(
776
            "SELECT `helppage` FROM `helppages` WHERE `ocpage`='&1' AND `language`='&2'",
777
            $ocPage,
778
            $opt['template']['default']['fallback_locale']
779
        );
780
        if (mysql_num_rows($rs) > 0) {
781
            $help_locale = $opt['template']['default']['fallback_locale'];
782
        }
783
    }
784
785
    if (mysql_num_rows($rs) > 0) {
786
        $record = sql_fetch_array($rs);
787
        $helpPage = $record['helppage'];
788
    } else {
789
        $helpPage = '';
790
    }
791
    mysql_free_result($rs);
792
793
    $imgTitle = $translate->t('Instructions', '', basename(__FILE__), __LINE__);
794
    $imgTitle = "alt='" . $imgTitle . "' title='" . $imgTitle . "'";
795
796
    if (substr($helpPage, 0, 1) == "!") {
797
        return "<a class='nooutline' href='" . substr($helpPage, 1) . "' " . $imgTitle . " target='_blank'>";
798
    } else {
799
        if ($helpPage != '' && isset($opt['locale'][$help_locale]['helpwiki'])) {
800
            return "<a class='nooutline' href='" . $opt['locale'][$help_locale]['helpwiki'] .
801
            str_replace(' ', '_', $helpPage) . "' " . $imgTitle . " target='_blank'>";
802
        }
803
    }
804
805
    return '';
806
}
807
808
function get_logtype_name($logtype, $language)
809
{
810
    return sqlValue(
811
        "SELECT IFNULL(`stt`.`text`, `log_types`.`en`)
812
         FROM `log_types`
813
         LEFT JOIN `sys_trans_text` `stt` ON `stt`.`trans_id`=`log_types`.`trans_id` AND `stt`.`lang`='" . sql_escape($language) . "'
814
         WHERE `log_types`.`id`='" . sql_escape($logtype) . "'",
815
        ''
816
    );
817
}
818