Completed
Push — development ( 8981a4...d3a488 )
by Stephen
18s
created

Templates::instance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 9
ccs 4
cts 6
cp 0.6667
crap 2.1481
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file has functions dealing with loading and precessing template files.
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * This file contains code covered by:
11
 * copyright:    2011 Simple Machines (http://www.simplemachines.org)
12
 * license:        BSD, See included LICENSE.TXT for terms and conditions.
13
 *
14
 * @version 1.1 Release Candidate 1
15
 *
16
 */
17
18
/**
19
 * Class Templates
20
 *
21
 * This class loads and processes template files and sheets.
22
 */
23
class Templates
24
{
25
	protected static $instance = null;
26
27
	/**
28
	 * Template directory's that we will be searching for the sheets
29
	 * @var array
30
	 */
31
	public $dirs = array();
32
33
	/**
34
	 * Template sheets that have not loaded
35
	 * @var array
36
	 */
37
	protected $delayed = array();
38
39
	/**
40
	 * Holds the file that are in the include list
41
	 * @var array
42
	 */
43
	protected $templates = array();
44
45
	/**
46
	 * Tracks if the default index.css has been loaded
47
	 * @var bool
48
	 */
49
	protected $default_loaded = false;
50
51
	/**
52
	 * Templates constructor.
53
	 */
54
	protected function __construct()
55
	{
56
		// We want to be able to figure out any errors...
57
		@ini_set('track_errors', '1');
58
	}
59
60
	/**
61
	 * Load a template - if the theme doesn't include it, use the default.
62
	 *
63
	 * What it does:
64
	 *
65
	 * - Loads a template file with the name template_name from the current, default, or base theme.
66
	 * - Detects a wrong default theme directory and tries to work around it.
67
	 * - Can be used to only load style sheets by using false as the template name
68
	 *   loading of style sheets with this function is deprecated, use loadCSSFile instead
69
	 * - If $this->dirs is empty, it delays the loading of the template
70
	 *
71
	 * @uses $this->requireTemplate() to actually load the file.
72
	 *
73
	 * @param string|false $template_name
74
	 * @param string[]|string $style_sheets any style sheets to load with the template
75
	 * @param bool $fatal = true if fatal is true, dies with an error message if the template cannot be found
76
	 *
77
	 * @return boolean|null
78
	 * @throws Elk_Exception
79
	 */
80 17
	public function load($template_name, $style_sheets = array(), $fatal = true)
81
	{
82
		// If we don't know yet the default theme directory, let's wait a bit.
83 17
		if (empty($this->dirs))
84 17
		{
85
			$this->delayed[] = array(
86
				$template_name,
87
				$style_sheets,
88
				$fatal
89
			);
90
91
			return;
92
		}
93
		// If instead we know the default theme directory and we have delayed something, it's time to process
94 17
		elseif (!empty($this->delayed))
95
		{
96
			foreach ($this->delayed as $val)
97
			{
98
				$this->requireTemplate($val[0], $val[1], $val[2]);
99
			}
100
101
			// Forget about them (load them only once)
102
			$this->delayed = array();
103
		}
104
105 17
		$this->requireTemplate($template_name, $style_sheets, $fatal);
106 17
	}
107
108
	/**
109
	 * <b>Internal function! Do not use it, use loadTemplate instead</b>
110
	 *
111
	 * What it does:
112
	 *
113
	 * - Loads a template file with the name template_name from the current, default, or base theme.
114
	 * - Detects a wrong default theme directory and tries to work around it.
115
	 * - Can be used to only load style sheets by using false as the template name
116
	 *  loading of style sheets with this function is deprecated, use loadCSSFile instead
117
	 *
118
	 * @uses $this->templateInclude() to include the file.
119
	 *
120
	 * @param string|false    $template_name
121
	 * @param string[]|string $style_sheets any style sheets to load with the template
122
	 * @param bool            $fatal = true if fatal is true, dies with an error message if the template cannot be found
123
	 *
124
	 * @return bool|null
125
	 * @throws Elk_Exception theme_template_error
126
	 */
127 17
	protected function requireTemplate($template_name, $style_sheets, $fatal)
128
	{
129 17
		global $context, $settings, $txt, $scripturl, $db_show_debug;
130
131 17
		if (!is_array($style_sheets))
132 17
		{
133
			$style_sheets = array($style_sheets);
134
		}
135
136 17
		if ($this->default_loaded === false)
137 17
		{
138
			loadCSSFile('index.css');
139
			$this->default_loaded = true;
140
		}
141
142
		// Any specific template style sheets to load?
143 17
		if (!empty($style_sheets))
144 17
		{
145
			trigger_error('Use of loadTemplate to add style sheets to the head is deprecated.', E_USER_DEPRECATED);
146
			$sheets = array();
147
			foreach ($style_sheets as $sheet)
148
			{
149
				$sheets[] = stripos('.css', $sheet) !== false ? $sheet : $sheet . '.css';
150
				if ($sheet == 'admin' && !empty($context['theme_variant']))
151
				{
152
					$sheets[] = $context['theme_variant'] . '/admin' . $context['theme_variant'] . '.css';
153
				}
154
			}
155
156
			loadCSSFile($sheets);
157
		}
158
159
		// No template to load?
160 17
		if ($template_name === false)
161 17
		{
162
			return true;
163
		}
164
165 17
		$loaded = false;
166 17
		$template_dir = '';
167 17
		foreach ($this->dirs as $template_dir)
168
		{
169 17
			if (file_exists($template_dir . '/' . $template_name . '.template.php'))
170 17
			{
171 17
				$loaded = true;
172 17
				$this->templateInclude($template_dir . '/' . $template_name . '.template.php', true);
173 17
				break;
174
			}
175 17
		}
176
177
		if ($loaded)
178 17
		{
179 17
			if ($db_show_debug === true)
180 17
			{
181
				Debug::instance()->add('templates', $template_name . ' (' . basename($template_dir) . ')');
182
			}
183
184
			// If they have specified an initialization function for this template, go ahead and call it now.
185 17
			if (function_exists('template_' . $template_name . '_init'))
186 17
			{
187 3
				call_user_func('template_' . $template_name . '_init');
188 3
			}
189 17
		}
190
		// Hmmm... doesn't exist?!  I don't suppose the directory is wrong, is it?
191
		elseif (!file_exists($settings['default_theme_dir']) && file_exists(BOARDDIR . '/themes/default'))
192
		{
193
			$settings['default_theme_dir'] = BOARDDIR . '/themes/default';
194
			$this->addDirectory($settings['default_theme_dir']);
195
196
			if (!empty($context['user']['is_admin']) && !isset($_GET['th']))
197
			{
198
				loadLanguage('Errors');
199
200
				if (!isset($context['security_controls_files']['title']))
201
				{
202
					$context['security_controls_files']['title'] = $txt['generic_warning'];
203
				}
204
205
				$context['security_controls_files']['errors']['theme_dir'] = '<a href="' . $scripturl . '?action=admin;area=theme;sa=list;th=1;' . $context['session_var'] . '=' . $context['session_id'] . '">' . $txt['theme_dir_wrong'] . '</a>';
206
			}
207
208
			loadTemplate($template_name);
209
		}
210
		// Cause an error otherwise.
211
		elseif ($template_name !== 'Errors' && $template_name !== 'index' && $fatal)
212
		{
213
			throw new Elk_Exception('theme_template_error', 'template', array((string) $template_name));
214
		}
215 View Code Duplication
		elseif ($fatal)
216
		{
217
			die(Errors::instance()->log_error(sprintf(isset($txt['theme_template_error']) ? $txt['theme_template_error'] : 'Unable to load themes/default/%s.template.php!', (string) $template_name), 'template'));
0 ignored issues
show
Coding Style Compatibility introduced by
The method requireTemplate() 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...
218
		}
219
		else
220
		{
221
			return false;
222
		}
223
224 17
		return true;
225
	}
226
227
	/**
228
	 * Load the template/language file using eval or require? (with eval we can show an error message!)
229
	 *
230
	 * What it does:
231
	 *
232
	 * - Loads the template or language file specified by filename.
233
	 * - Uses eval unless disableTemplateEval is enabled.
234
	 * - Outputs a parse error if the file did not exist or contained errors.
235
	 * - Attempts to detect the error and line, and show detailed information.
236
	 *
237
	 * @param string $filename
238
	 * @param bool $once = false, if true only includes the file once (like include_once)
239
	 */
240 27
	public function templateInclude($filename, $once = false)
241
	{
242
		// I know this looks weird but this is used to include $txt files. If the parent doesn't declare them global
243
		// the scope will be local to this function. IOW, don't remove this line!
244 27
		global $txt;
245
246
		// Don't include the file more than once, if $once is true.
247 27
		if ($once && in_array($filename, $this->templates))
248 27
		{
249 16
			return;
250
		}
251
		// Add this file to the include list, whether $once is true or not.
252
		else
253
		{
254 18
			$this->templates[] = $filename;
255
		}
256
257
		// Load it if we find it
258 18
		$file_found = file_exists($filename);
259
260 18
		if ($once && $file_found)
261 18
		{
262 4
			require_once($filename);
263 4
		}
264 17
		elseif ($file_found)
265
		{
266 17
			require($filename);
267 17
		}
268
269 18
		if ($file_found !== true)
270 18
		{
271
			$this->templateNotFound($filename);
272
		}
273 18
	}
274
275
	/**
276
	 * Displays an error when a template is not found or has syntax errors preventing its loading
277
	 *
278
	 * @param string $filename
279
	 */
280
	protected function templateNotFound($filename)
281
	{
282
		global $context, $txt, $scripturl, $modSettings, $boardurl;
283
		global $maintenance, $mtitle, $mmessage;
284
285
		obStart(!empty($modSettings['enableCompressedOutput']));
286
287
		// Don't cache error pages!!
288
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
289
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
290
		header('Cache-Control: no-cache');
291
292
		if (!isset($txt['template_parse_error']))
293
		{
294
			$txt['template_parse_error'] = 'Template Parse Error!';
295
			$txt['template_parse_error_message'] = 'It seems something has gone sour on the forum with the template system.  This problem should only be temporary, so please come back later and try again.  If you continue to see this message, please contact the administrator.<br /><br />You can also try <a href="javascript:location.reload();">refreshing this page</a>.';
296
			$txt['template_parse_error_details'] = 'There was a problem loading the <span style="font-family: monospace;"><strong>%1$s</strong></span> template or language file.  Please check the syntax and try again - remember, single quotes (<span style="font-family: monospace;">\'</span>) often have to be escaped with a slash (<span style="font-family: monospace;">\\</span>).  To see more specific error information from PHP, try <a href="%2$s%1$s" class="extern">accessing the file directly</a>.<br /><br />You may want to try to <a href="javascript:location.reload();">refresh this page</a> or <a href="%3$s">use the default theme</a>.';
297
			$txt['template_parse_undefined'] = 'An undefined error occurred during the parsing of this template';
298
		}
299
300
		// First, let's get the doctype and language information out of the way.
301
		echo '<!DOCTYPE html>
302
<html ', !empty($context['right_to_left']) ? 'dir="rtl"' : '', '>
303
	<head>
304
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
305
306
		if (!empty($maintenance) && !allowedTo('admin_forum'))
307
		{
308
			echo '
309
		<title>', $mtitle, '</title>
310
	</head>
311
	<body>
312
		<h3>', $mtitle, '</h3>
313
		', $mmessage, '
314
	</body>
315
</html>';
316
		}
317
		elseif (!allowedTo('admin_forum'))
318
		{
319
			echo '
320
		<title>', $txt['template_parse_error'], '</title>
321
	</head>
322
	<body>
323
		<h3>', $txt['template_parse_error'], '</h3>
324
		', $txt['template_parse_error_message'], '
325
	</body>
326
</html>';
327
		}
328
		else
329
		{
330
			require_once(SUBSDIR . '/Package.subs.php');
331
332
			$error = fetch_web_data($boardurl . strtr($filename, array(BOARDDIR => '', strtr(BOARDDIR, '\\', '/') => '')));
333
			if (empty($error) && ini_get('track_errors') && !empty($php_errormsg))
334
			{
335
				$error = $php_errormsg;
336
			}
337
			elseif (empty($error))
338
			{
339
				$error = $txt['template_parse_undefined'];
340
			}
341
342
			$error = strtr($error, array('<b>' => '<strong>', '</b>' => '</strong>'));
343
344
			echo '
345
		<title>', $txt['template_parse_error'], '</title>
346
	</head>
347
	<body>
348
		<h3>', $txt['template_parse_error'], '</h3>
349
		', sprintf($txt['template_parse_error_details'], strtr($filename, array(BOARDDIR => '', strtr(BOARDDIR, '\\', '/') => '')), $boardurl, $scripturl . '?theme=1');
350
351
			if (!empty($error))
352
			{
353
				echo '
354
		<hr />
355
356
		<div style="margin: 0 20px;"><span style="font-family: monospace;">', strtr(strtr($error, array('<strong>' . BOARDDIR => '<strong>...', '<strong>' . strtr(BOARDDIR, '\\', '/') => '<strong>...')), '\\', '/'), '</span></div>';
357
			}
358
359
			// I know, I know... this is VERY COMPLICATED.  Still, it's good.
360
			if (preg_match('~ <strong>(\d+)</strong><br( /)?' . '>$~i', $error, $match) != 0)
361
			{
362
				$data = file($filename);
363
				$data2 = highlight_php_code(implode('', $data));
364
				$data2 = preg_split('~\<br( /)?\>~', $data2);
365
366
				// Fix the PHP code stuff...
367
				if (!isBrowser('gecko'))
368
				{
369
					$data2 = str_replace("\t", '<span style="white-space: pre;">' . "\t" . '</span>', $data2);
370
				}
371
				else
372
				{
373
					$data2 = str_replace('<pre style="display: inline;">' . "\t" . '</pre>', "\t", $data2);
374
				}
375
376
				// Now we get to work around a bug in PHP where it doesn't escape <br />s!
377
				$j = -1;
378
				foreach ($data as $line)
379
				{
380
					$j++;
381
382
					if (substr_count($line, '<br />') == 0)
383
					{
384
						continue;
385
					}
386
387
					$n = substr_count($line, '<br />');
388
					for ($i = 0; $i < $n; $i++)
389
					{
390
						$data2[$j] .= '&lt;br /&gt;' . $data2[$j + $i + 1];
391
						unset($data2[$j + $i + 1]);
392
					}
393
					$j += $n;
394
				}
395
				$data2 = array_values($data2);
396
				array_unshift($data2, '');
397
398
				echo '
399
		<div style="margin: 2ex 20px; width: 96%; overflow: auto;"><pre style="margin: 0;">';
400
401
				// Figure out what the color coding was before...
402
				$line = max($match[1] - 9, 1);
403
				$last_line = '';
404
				for ($line2 = $line - 1; $line2 > 1; $line2--)
405
				{
406
					if (strpos($data2[$line2], '<') !== false)
407
					{
408
						if (preg_match('~(<[^/>]+>)[^<]*$~', $data2[$line2], $color_match) != 0)
409
						{
410
							$last_line = $color_match[1];
411
						}
412
						break;
413
					}
414
				}
415
416
				// Show the relevant lines...
417
				for ($n = min($match[1] + 4, count($data2) + 1); $line <= $n; $line++)
418
				{
419
					if ($line == $match[1])
420
					{
421
						echo '</pre><div style="background: #ffb0b5;"><pre style="margin: 0;">';
422
					}
423
424
					echo '<span style="color: black;">', sprintf('%' . strlen($n) . 's', $line), ':</span> ';
425
					if (isset($data2[$line]) && $data2[$line] != '')
426
					{
427
						echo substr($data2[$line], 0, 2) == '</' ? preg_replace('~^</[^>]+>~', '', $data2[$line]) : $last_line . $data2[$line];
428
					}
429
430
					if (isset($data2[$line]) && preg_match('~(<[^/>]+>)[^<]*$~', $data2[$line], $color_match) != 0)
431
					{
432
						$last_line = $color_match[1];
433
						echo '</', substr($last_line, 1, 4), '>';
434
					}
435
					elseif ($last_line != '' && strpos($data2[$line], '<') !== false)
436
					{
437
						$last_line = '';
438
					}
439
					elseif ($last_line != '' && $data2[$line] != '')
440
					{
441
						echo '</', substr($last_line, 1, 4), '>';
442
					}
443
444
					if ($line == $match[1])
445
					{
446
						echo '</pre></div><pre style="margin: 0;">';
447
					}
448
					else
449
					{
450
						echo "\n";
451
					}
452
				}
453
454
				echo '</pre></div>';
455
			}
456
457
			echo '
458
	</body>
459
</html>';
460
		}
461
462
		die;
0 ignored issues
show
Coding Style Compatibility introduced by
The method templateNotFound() 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...
463
	}
464
465
	/**
466
	 * Load a sub-template.
467
	 *
468
	 * What it does:
469
	 *
470
	 * - loads the sub template specified by sub_template_name, which must be in an already-loaded template.
471
	 * - if ?debug is in the query string, shows administrators a marker after every sub template
472
	 * for debugging purposes.
473
	 *
474
	 * @todo get rid of reading $_REQUEST directly
475
	 *
476
	 * @param string      $sub_template_name
477
	 * @param bool|string $fatal = false, $fatal = true is for templates that
478
	 *   shouldn't get a 'pretty' error screen 'ignore' to skip
479
	 *
480
	 * @throws Elk_Exception theme_template_error
481
	 */
482
	public function loadSubTemplate($sub_template_name, $fatal = false)
483
	{
484
		global $txt, $db_show_debug;
485
486
		if ($sub_template_name === false)
487
		{
488
			return;
489
		}
490
491
		if ($db_show_debug === true)
492
		{
493
			Debug::instance()->add('sub_templates', $sub_template_name);
494
		}
495
496
		// Figure out what the template function is named.
497
		$theme_function = 'template_' . $sub_template_name;
498
499
		if (function_exists($theme_function))
500
		{
501
			$this->_templateDebug($sub_template_name, true);
502
			$theme_function();
0 ignored issues
show
Security Code Execution introduced by
$theme_function can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST, and $_POST is passed to Data_Validator::is_valid()
    in sources/controllers/Post.controller.php on line 883
  2. $data is passed to Data_Validator::validate()
    in sources/subs/DataValidator.class.php on line 147
  3. Data_Validator::$_data is assigned
    in sources/subs/DataValidator.class.php on line 249
  4. Tainted property Data_Validator::$_data is read
    in sources/subs/DataValidator.class.php on line 281
  5. Data_Validator::validation_data() returns tainted data
    in sources/subs/HttpReq.class.php on line 359
  6. HttpReq::cleanValue() returns tainted data, and HttpReq::$_param is assigned
    in sources/subs/HttpReq.class.php on line 219
  7. Tainted property HttpReq::$_param is read
    in sources/subs/HttpReq.class.php on line 278
  8. HttpReq::getQuery() returns tainted data, and $context is assigned
    in sources/controllers/Unread.controller.php on line 92
  9. $context is assigned
    in sources/controllers/Unread.controller.php on line 93
  10. $context is assigned
    in sources/controllers/Unread.controller.php on line 104
  11. $context is assigned
    in sources/controllers/Unread.controller.php on line 126
  12. $context is assigned
    in sources/controllers/Unread.controller.php on line 133
  13. $context is assigned
    in sources/controllers/Unread.controller.php on line 134
  14. $context['sub_template'] is passed to Template_Layers::add()
    in sources/controllers/Unread.controller.php on line 136
  15. $layer is passed to Priority::add()
    in sources/subs/TemplateLayers.class.php on line 50
  16. Priority::$_all_general is assigned
    in sources/subs/Priority.class.php on line 88
  17. Tainted property Priority::$_all_general is read, and $this->_all_general is passed through array_merge()
    in sources/subs/Priority.class.php on line 206
  18. $all_entities is assigned
    in sources/subs/Priority.class.php on line 204
  19. $all_entities is passed through array_keys(), and Priority::$_sorted_entities is assigned
    in sources/subs/Priority.class.php on line 275
  20. Tainted property Priority::$_sorted_entities is read
    in sources/subs/TemplateLayers.class.php on line 139
  21. Template_Layers::prepareContext() returns tainted data, and $layer is assigned
    in themes/default/Theme.php on line 79
  22. $layer . '_above' is passed to loadSubTemplate()
    in themes/default/Theme.php on line 81
  23. $sub_template_name is passed to Templates::loadSubTemplate()
    in sources/Load.php on line 1912
  24. $theme_function is assigned
    in sources/Templates.class.php on line 497

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...
503
		}
504
		elseif ($fatal === false)
505
		{
506
			throw new Elk_Exception('theme_template_error', 'template', array((string) $sub_template_name));
507
		}
508 View Code Duplication
		elseif ($fatal !== 'ignore')
509
		{
510
			die(Errors::instance()->log_error(sprintf(isset($txt['theme_template_error']) ? $txt['theme_template_error'] : 'Unable to load the %s sub template!', (string) $sub_template_name), 'template'));
0 ignored issues
show
Coding Style Compatibility introduced by
The method loadSubTemplate() 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...
511
		}
512
513
		$this->_templateDebug($sub_template_name);
514
	}
515
516
	/**
517
	 * Are we showing debugging for templates?  Just make sure not to do it before the doctype...
518
	 *
519
	 * @param bool $start
520
	 * @param string $sub_template_name
521
	 */
522
	private function _templateDebug($sub_template_name, $start = false)
523
	{
524
		if (isset($_REQUEST['debug']) && allowedTo('admin_forum') && !in_array($sub_template_name, array('init')) && ob_get_length() > 0 && !isset($_REQUEST['xml']) && !isset($_REQUEST['api']))
525
		{
526
			echo '
527
 				<div class="warningbox">---- ', $sub_template_name, ' ', ($start ? 'starts' : 'ends'), ' ----</div>';
0 ignored issues
show
Security Cross-Site Scripting introduced by
$sub_template_name can contain request data and is used in output context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST, and $_POST is passed to Data_Validator::is_valid()
    in sources/controllers/Post.controller.php on line 883
  2. $data is passed to Data_Validator::validate()
    in sources/subs/DataValidator.class.php on line 147
  3. Data_Validator::$_data is assigned
    in sources/subs/DataValidator.class.php on line 249
  4. Tainted property Data_Validator::$_data is read
    in sources/subs/DataValidator.class.php on line 281
  5. Data_Validator::validation_data() returns tainted data
    in sources/subs/HttpReq.class.php on line 359
  6. HttpReq::cleanValue() returns tainted data, and HttpReq::$_param is assigned
    in sources/subs/HttpReq.class.php on line 219
  7. Tainted property HttpReq::$_param is read
    in sources/subs/HttpReq.class.php on line 278
  8. HttpReq::getQuery() returns tainted data, and $context is assigned
    in sources/controllers/Unread.controller.php on line 92
  9. $context is assigned
    in sources/controllers/Unread.controller.php on line 93
  10. $context is assigned
    in sources/controllers/Unread.controller.php on line 104
  11. $context is assigned
    in sources/controllers/Unread.controller.php on line 126
  12. $context is assigned
    in sources/controllers/Unread.controller.php on line 133
  13. $context is assigned
    in sources/controllers/Unread.controller.php on line 134
  14. $context['sub_template'] is passed to Template_Layers::add()
    in sources/controllers/Unread.controller.php on line 136
  15. $layer is passed to Priority::add()
    in sources/subs/TemplateLayers.class.php on line 50
  16. Priority::$_all_general is assigned
    in sources/subs/Priority.class.php on line 88
  17. Tainted property Priority::$_all_general is read, and $this->_all_general is passed through array_merge()
    in sources/subs/Priority.class.php on line 206
  18. $all_entities is assigned
    in sources/subs/Priority.class.php on line 204
  19. $all_entities is passed through array_keys(), and Priority::$_sorted_entities is assigned
    in sources/subs/Priority.class.php on line 275
  20. Tainted property Priority::$_sorted_entities is read
    in sources/subs/TemplateLayers.class.php on line 139
  21. Template_Layers::prepareContext() returns tainted data, and $layer is assigned
    in themes/default/Theme.php on line 79
  22. $layer . '_above' is passed to loadSubTemplate()
    in themes/default/Theme.php on line 81
  23. $sub_template_name is passed to Templates::loadSubTemplate()
    in sources/Load.php on line 1912
  24. $sub_template_name is passed to Templates::_templateDebug()
    in sources/Templates.class.php on line 501

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

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...
528
		}
529
	}
530
531
	/**
532
	 * Reloads the directory stack/queue to ensure they are searched in the proper order
533
	 *
534
	 * @param array $settings
535
	 */
536 7
	public function reloadDirectories(array $settings)
537
	{
538 7
		$this->dirs = array();
539
540 7
		if (!empty($settings['theme_dir']))
541 7
		{
542 7
			$this->addDirectory($settings['theme_dir']);
543 7
		}
544
545
		// Based on theme (if there is one).
546 7
		if (!empty($settings['base_theme_dir']))
547 7
		{
548
			$this->addDirectory($settings['base_theme_dir']);
549
		}
550
551
		// Lastly the default theme.
552 7
		if ($settings['theme_dir'] !== $settings['default_theme_dir'])
553 7
		{
554
			$this->addDirectory($settings['default_theme_dir']);
555
		}
556 7
	}
557
558
	/**
559
	 * Add a template directory to the search stack
560
	 *
561
	 * @param string $dir
562
	 *
563
	 * @return $this
564
	 */
565 7
	public function addDirectory($dir)
566
	{
567 7
		$this->dirs[] = (string) $dir;
568
569 7
		return $this;
570
	}
571
572
	/**
573
	 * Sets the directory array in to the class
574
	 *
575
	 * @param array $dirs
576
	 */
577
	public function setDirectories(array $dirs)
578
	{
579
		$this->dirs = $dirs;
580
	}
581
582
	/**
583
	 * Returns if theme directory's have been loaded
584
	 *
585
	 * @return bool
586
	 */
587 1
	public function hasDirectories()
588
	{
589 1
		return !empty($this->dirs);
590
	}
591
592
	/**
593
	 * Return the directory's that have been loaded
594
	 *
595
	 * @return array
596
	 */
597
	public function getTemplateDirectories()
598
	{
599
		return $this->dirs;
600
	}
601
602
	/**
603
	 * Return the template sheet stack
604
	 *
605
	 * @return array
606
	 */
607
	public function getIncludedTemplates()
608
	{
609
		return $this->templates;
610
	}
611
612
	/**
613
	 * Find and return Templates instance if it exists,
614
	 * or create a new instance
615
	 *
616
	 * @return Templates
617
	 */
618 27
	public static function instance()
619
	{
620 27
		if (self::$instance === null)
621 27
		{
622
			self::$instance = new Templates;
623
		}
624
625 27
		return self::$instance;
626
	}
627
}
628