GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( ba9f3c...6bcce1 )
by gyeong-won
07:26
created

TemplateHandler::isSafeguard()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 0
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
1
<?php
2
/* Copyright (C) NAVER <http://www.navercorp.com> */
3
4
/**
5
 * @class TemplateHandler
6
 * @author NAVER ([email protected])
7
 * template compiler
8
 * @version 0.1
9
 * @remarks It compiles template file by using regular expression into php
10
 *          code, and XE caches compiled code for further uses
11
 */
12
class TemplateHandler
13
{
14
15
	private $compiled_path = 'files/cache/template_compiled/'; ///< path of compiled caches files
16
	private $path = NULL; ///< target directory
17
	private $filename = NULL; ///< target filename
18
	private $file = NULL; ///< target file (fullpath)
19
	private $xe_path = NULL;  ///< XpressEngine base path
20
	private $web_path = NULL; ///< tpl file web path
21
	private $compiled_file = NULL; ///< tpl file web path
22
	private $config = NULL;
23
	private $skipTags = NULL;
24
	private $handler_mtime = 0;
25
	private $safeguard = false;
26
	static private $rootTpl = NULL;
27
28
	/**
29
	 * constructor
30
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
31
	 */
32
	public function __construct()
33
	{
34
		ini_set('pcre.jit', "0");
35
		$this->xe_path = rtrim(getScriptPath(), '/');
36
		$this->compiled_path = _XE_PATH_ . $this->compiled_path;
37
		$this->config = new stdClass();
38
39
		$this->ignoreEscape = array(
0 ignored issues
show
Bug introduced by
The property ignoreEscape does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
40
			'html_content' => function ($m) {
41
				$list = array(
42
					'$content', // 레이아웃 등
43
					'$editor', // 에디터 출력
44
					'$page_content', // page 모듈
45
					'$setup_content', // 모듈 추가 설정 페이지
46
					'$grant_content', // 모듈 권한 설정 페이지
47
					'$skin_content', // 모듈 스킨 설정 페이지
48
					'$extra_vars_content', // 모듈 확장변수 설정 페이지
49
					'Context::getHtmlHeader()',
50
					'Context::getHtmlFooter()',
51
					'Context::getBodyHeader()'
52
				);
53
				return in_array($m[1], $list);
54
			},
55
			'url' => function ($m) {
56
				$list = array(
57
					'getUrl',
58
					'getNotEncodedUrl',
59
					'getAutoEncodedUrl',
60
					'getFullUrl',
61
					'getNotEncodedFullUrl',
62
					'getSiteUrl',
63
					'getNotEncodedSiteUrl',
64
					'getFullSiteUrl',
65
					'getCurrentPageUrl',
66
					'getCurrentPageUrl',
67
				);
68
				return in_array(array_shift(explode('(', $m[1])), $list);
0 ignored issues
show
Bug introduced by
explode('(', $m[1]) cannot be passed to array_shift() as the parameter $array expects a reference.
Loading history...
69
			},
70
			'methods' => function ($m) {
71
				$list = array(
72
					'getEditor',
73
					'getCommentEditor',
74
					'getFormHTML', // 확장변수
75
					'getContent',
76
					'getSignature', // 회원 서명
77
					'printExtraImages', // new, file 아이콘 등
78
				);
79
				return preg_match('/\-\>(' . implode('|', $list) . ')\(/', $m[1]);
80
			},
81
			'functions' => function ($m) {
82
				$list = array(
83
					'htmlspecialchars',
84
				);
85
				return preg_match('/^(' . implode('|', $list) . ')\(/', $m[1]);
86
			},
87
			'lang' => function ($m) {
88
				// 다국어
89
				return preg_match('/^\$lang\-\>/', trim($m[1]));
90
			}
91
		);
92
93
		$this->dbinfo = Context::getDBInfo();
0 ignored issues
show
Bug introduced by
The property dbinfo does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
94
	}
95
96
	/**
97
	 * returns TemplateHandler's singleton object
98
	 * @return TemplateHandler instance
99
	 */
100
	static public function &getInstance()
101
	{
102
		static $oTemplate = NULL;
103
104
		if(__DEBUG__ == 3)
105
		{
106
			if(!isset($GLOBALS['__TemplateHandlerCalled__']))
107
			{
108
				$GLOBALS['__TemplateHandlerCalled__'] = 1;
109
			}
110
			else
111
			{
112
				$GLOBALS['__TemplateHandlerCalled__']++;
113
			}
114
		}
115
116
		if(!$oTemplate)
117
		{
118
			$oTemplate = new TemplateHandler();
119
		}
120
121
		return $oTemplate;
122
	}
123
124
	/**
125
	 * set variables for template compile
126
	 * @param string $tpl_path
127
	 * @param string $tpl_filename
128
	 * @param string $tpl_file
129
	 * @return void
130
	 */
131
	protected function init($tpl_path, $tpl_filename, $tpl_file = '')
132
	{
133
		// verify arguments
134
		if(substr($tpl_path, -1) != '/')
135
		{
136
			$tpl_path .= '/';
137
		}
138
		if(!is_dir($tpl_path))
139
		{
140
			return;
141
		}
142
		if(!file_exists($tpl_path . $tpl_filename) && file_exists($tpl_path . $tpl_filename . '.html'))
143
		{
144
			$tpl_filename .= '.html';
145
		}
146
147
		// create tpl_file variable
148
		if(!$tpl_file)
149
		{
150
			$tpl_file = $tpl_path . $tpl_filename;
151
		}
152
153
		// set template file infos.
154
		$this->path = $tpl_path;
155
		$this->filename = $tpl_filename;
156
		$this->file = $tpl_file;
157
158
		$this->web_path = $this->xe_path . '/' . ltrim(preg_replace('@^' . preg_quote(_XE_PATH_, '@') . '|\./@', '', $this->path), '/');
159
160
		// get compiled file name
161
		$hash = md5($this->file . __XE_VERSION__);
162
		$this->compiled_file = "{$this->compiled_path}{$hash}.compiled.php";
163
164
		$this->safeguard = $this->isSafeguard();
165
166
		// compare various file's modified time for check changed
167
		$this->handler_mtime = filemtime(__FILE__);
168
169
		$skip = array('');
0 ignored issues
show
Unused Code introduced by
$skip 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...
170
	}
171
172
	/**
173
	 * compiles specified tpl file and execution result in Context into resultant content
174
	 * @param string $tpl_path path of the directory containing target template file
175
	 * @param string $tpl_filename target template file's name
176
	 * @param string $tpl_file if specified use it as template file's full path
177
	 * @return string Returns compiled result in case of success, NULL otherwise
178
	 */
179
	public function compile($tpl_path, $tpl_filename, $tpl_file = '')
180
	{
181
		$buff = false;
182
183
		// store the starting time for debug information
184
		if(__DEBUG__ == 3)
185
		{
186
			$start = getMicroTime();
187
		}
188
189
		// initiation
190
		$this->init($tpl_path, $tpl_filename, $tpl_file);
191
192
		// if target file does not exist exit
193
		if(!$this->file || !file_exists($this->file))
194
		{
195
			return "Err : '{$this->file}' template file does not exists.";
196
		}
197
198
		// for backward compatibility
199
		if(is_null(self::$rootTpl))
200
		{
201
			self::$rootTpl = $this->file;
202
		}
203
204
		$source_template_mtime = filemtime($this->file);
205
		$latest_mtime = $source_template_mtime > $this->handler_mtime ? $source_template_mtime : $this->handler_mtime;
206
207
		// cache control
208
		$oCacheHandler = CacheHandler::getInstance('template');
209
210
		// get cached buff
211
		if($oCacheHandler->isSupport())
212
		{
213
			$cache_key = 'template:' . $this->file;
214
			$buff = $oCacheHandler->get($cache_key, $latest_mtime);
215
		}
216
		else
217
		{
218
			if(is_readable($this->compiled_file) && filemtime($this->compiled_file) > $latest_mtime && filesize($this->compiled_file))
219
			{
220
				$buff = 'file://' . $this->compiled_file;
221
			}
222
		}
223
224
		if($buff === FALSE)
225
		{
226
			$buff = $this->parse();
227
			if($oCacheHandler->isSupport())
228
			{
229
				$oCacheHandler->put($cache_key, $buff);
0 ignored issues
show
Bug introduced by
The variable $cache_key does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
230
			}
231
			else
232
			{
233
				FileHandler::writeFile($this->compiled_file, $buff);
234
			}
235
		}
236
237
		$output = $this->_fetch($buff);
0 ignored issues
show
Bug introduced by
It seems like $buff can also be of type boolean or null; however, TemplateHandler::_fetch() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
238
239
		if($__templatehandler_root_tpl == $this->file)
0 ignored issues
show
Bug introduced by
The variable $__templatehandler_root_tpl seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
240
		{
241
			$__templatehandler_root_tpl = null;
0 ignored issues
show
Unused Code introduced by
$__templatehandler_root_tpl 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...
242
		}
243
244
		// store the ending time for debug information
245
		if(__DEBUG__ == 3)
246
		{
247
			$GLOBALS['__template_elapsed__'] += getMicroTime() - $start;
0 ignored issues
show
Bug introduced by
The variable $start does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
248
		}
249
250
		return $output;
251
	}
252
253
	/**
254
	 * compile specified file and immediately return
255
	 * @param string $tpl_path path of the directory containing target template file
256
	 * @param string $tpl_filename target template file's name
257
	 * @return string Returns compiled content in case of success or NULL in case of failure
258
	 */
259
	public function compileDirect($tpl_path, $tpl_filename)
260
	{
261
		$this->init($tpl_path, $tpl_filename, null);
262
263
		// if target file does not exist exit
264
		if(!$this->file || !file_exists($this->file))
265
		{
266
			Context::close();
267
			exit("Cannot find the template file: '{$this->file}'");
268
		}
269
270
		return $this->parse();
271
	}
272
273
	/**
274
	 * parse syntax.
275
	 * @param string $buff template file
276
	 * @return string compiled result in case of success or NULL in case of error
277
	 */
278
	protected function parse($buff = null)
279
	{
280
		if(is_null($buff))
281
		{
282
			if(!is_readable($this->file))
283
			{
284
				return;
285
			}
286
287
			// read tpl file
288
			$buff = FileHandler::readFile($this->file);
289
		}
290
291
		// HTML tags to skip
292
		if(is_null($this->skipTags))
293
		{
294
			$this->skipTags = array('marquee');
295
		}
296
297
		// reset config for this buffer (this step is necessary because we use a singleton for every template)
298
		$previous_config = clone $this->config;
299
		$this->config = new stdClass();
300
		$this->config->autoescape = null;
301
302
		if(preg_match('/\<config( [^\>\/]+)/', $buff, $config_match))
303
		{
304
			if(preg_match_all('@ (?<name>\w+)="(?<value>[^"]+)"@', $config_match[1], $config_matches, PREG_SET_ORDER))
305
			{
306
				foreach($config_matches as $config_match)
307
				{
308
					if($config_match['name'] === 'autoescape')
309
					{
310
						$this->config->autoescape = $config_match['value'];
311
					}
312
				}
313
			}
314
		}
315
316
		if($this->config->autoescape === 'on') $this->safeguard = true;
317
318
		// replace comments
319
		$buff = preg_replace('@<!--//.*?-->@s', '', $buff);
320
321
		// replace value of src in img/input/script tag
322
		$buff = preg_replace_callback('/<(?:img|input|script)(?:[^<>]*?)(?(?=cond=")(?:cond="[^"]+"[^<>]*)+|)[^<>]* src="(?!(?:https?|file):\/\/|[\/\{])([^"]+)"/is', array($this, '_replacePath'), $buff);
323
324
		// replace loop and cond template syntax
325
		$buff = $this->_parseInline($buff);
326
327
		// include, unload/load, import
328
		$buff = preg_replace_callback('/{(@[\s\S]+?|(?=\$\w+|_{1,2}[A-Z]+|[!\(+-]|\w+(?:\(|::)|\d+|[\'"].*?[\'"]).+?)}|<(!--[#%])?(include|import|(un)?load(?(4)|(?:_js_plugin)?)|config)(?(2)\(["\']([^"\']+)["\'])(.*?)(?(2)\)--|\/)>|<!--(@[a-z@]*)([\s\S]*?)-->(\s*)/', array($this, '_parseResource'), $buff);
329
330
		// remove block which is a virtual tag
331
		$buff = preg_replace('@</?block\s*>@is', '', $buff);
332
333
		// form auto generation
334
		$temp = preg_replace_callback('/(<form(?:<\?php.+?\?>|[^<>]+)*?>)(.*?)(<\/form>)/is', array($this, '_compileFormAuthGeneration'), $buff);
335
		if($temp)
336
		{
337
			$buff = $temp;
338
		}
339
340
		// prevent from calling directly before writing into file
341
		$buff = '<?php if(!defined("__XE__"))exit;?>' . $buff;
342
343
		// remove php script reopening
344
		$buff = preg_replace(array('/(\n|\r\n)+/', '/(;)?( )*\?\>\<\?php([\n\t ]+)?/'), array("\n", ";\n"), $buff);
345
346
		// restore config to previous value
347
		$this->config = $previous_config;
348
349
		return $buff;
350
	}
351
352
	/**
353
	 * preg_replace_callback handler
354
	 * 1. remove ruleset from form tag
355
	 * 2. add hidden tag with ruleset value
356
	 * 3. if empty default hidden tag, generate hidden tag (ex:mid, vid, act...)
357
	 * 4. generate return url, return url use in server side validator
358
	 * @param array $matches
359
	 * @return string
360
	 */
361
	private function _compileFormAuthGeneration($matches)
362
	{
363
		// form ruleset attribute move to hidden tag
364
		if($matches[1])
365
		{
366
			preg_match('/ruleset="([^"]*?)"/is', $matches[1], $m);
367
			if($m[0])
368
			{
369
				$matches[1] = preg_replace('/' . addcslashes($m[0], '?$') . '/i', '', $matches[1]);
370
371
				if(strpos($m[1], '@') !== FALSE)
372
				{
373
					$path = str_replace('@', '', $m[1]);
374
					$path = './files/ruleset/' . $path . '.xml';
375
				}
376
				else if(strpos($m[1], '#') !== FALSE)
377
				{
378
					$fileName = str_replace('#', '', $m[1]);
379
					$fileName = str_replace('<?php echo ', '', $fileName);
380
					$fileName = str_replace(' ?>', '', $fileName);
381
					$path = '#./files/ruleset/' . $fileName . '.xml';
382
383
					preg_match('@(?:^|\.?/)(modules/[\w-]+)@', $this->path, $mm);
384
					$module_path = $mm[1];
385
					list($rulsetFile) = explode('.', $fileName);
386
					$autoPath = $module_path . '/ruleset/' . $rulsetFile . '.xml';
387
					$m[1] = $rulsetFile;
388
				}
389
				else if(preg_match('@(?:^|\.?/)(modules/[\w-]+)@', $this->path, $mm))
390
				{
391
					$module_path = $mm[1];
392
					$path = $module_path . '/ruleset/' . $m[1] . '.xml';
393
				}
394
395
				$matches[2] = '<input type="hidden" name="ruleset" value="' . $m[1] . '" />' . $matches[2];
396
				//assign to addJsFile method for js dynamic recache
397
				$matches[1] = '<?php Context::addJsFile("' . $path . '", FALSE, "", 0, "body", TRUE, "' . $autoPath . '") ?' . '>' . $matches[1];
0 ignored issues
show
Bug introduced by
The variable $path does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $autoPath does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
398
			}
399
		}
400
401
		// if not exists default hidden tag, generate hidden tag
402
		preg_match_all('/<input[^>]* name="(act|mid|vid)"/is', $matches[2], $m2);
403
		$checkVar = array('act', 'mid', 'vid');
404
		$resultArray = array_diff($checkVar, $m2[1]);
405
		if(is_array($resultArray))
406
		{
407
			$generatedHidden = '';
408
			foreach($resultArray AS $key => $value)
409
			{
410
				$generatedHidden .= '<input type="hidden" name="' . $value . '" value="<?php echo $__Context->' . $value . ' ?>" />';
411
			}
412
			$matches[2] = $generatedHidden . $matches[2];
413
		}
414
415
		// return url generate
416
		if(!preg_match('/no-error-return-url="true"/i', $matches[1]))
417
		{
418
			preg_match('/<input[^>]*name="error_return_url"[^>]*>/is', $matches[2], $m3);
419
			if(!$m3[0])
420
				$matches[2] = '<input type="hidden" name="error_return_url" value="<?php echo htmlspecialchars(getRequestUriByServerEnviroment(), ENT_COMPAT | ENT_HTML401, \'UTF-8\', false) ?>" />' . $matches[2];
421
		}
422
		else
423
		{
424
			$matches[1] = preg_replace('/no-error-return-url="true"/i', '', $matches[1]);
425
		}
426
427
		$matches[0] = '';
428
		return implode($matches);
429
	}
430
431
	/**
432
	 * fetch using ob_* function
433
	 * @param string $buff if buff is not null, eval it instead of including compiled template file
434
	 * @return string
435
	 */
436
	private function _fetch($buff)
437
	{
438
		if(!$buff)
439
		{
440
			return;
441
		}
442
443
		$__Context = &$GLOBALS['__Context__'];
444
		$__Context->tpl_path = $this->path;
445
446
		if($_SESSION['is_logged'])
447
		{
448
			$__Context->logged_info = Context::get('logged_info');
449
		}
450
451
		$level = ob_get_level();
452
		ob_start();
453
		if(substr($buff, 0, 7) == 'file://')
454
		{
455
			if(__DEBUG__)
456
			{
457
				//load cache file from disk
458
				$eval_str = FileHandler::readFile(substr($buff, 7));
459
				$eval_str_buffed = "?>" . $eval_str;
460
				@eval($eval_str_buffed);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
461
				$error_info = error_get_last();
462
				//parse error
463
				if ($error_info['type'] == 4)
464
				{
465
				    throw new Exception("Error Parsing Template - {$error_info['message']} in template file {$this->file}");
466
				}
467
			}
468
			else
469
			{
470
				include(substr($buff, 7));
471
			}
472
		}
473
		else
474
		{
475
			$eval_str = "?>" . $buff;
476
			@eval($eval_str);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
477
			$error_info = error_get_last();
478
			//parse error
479
			if ($error_info['type'] == 4)
480
			{
481
			    throw new Exception("Error Parsing Template - {$error_info['message']} in template file {$this->file}");
482
			}
483
		}
484
485
		$contents = '';
486
		while (ob_get_level() - $level > 0) {
487
			$contents .= ob_get_contents();
488
			ob_end_clean();
489
		}
490
		return $contents;
491
	}
492
493
	/**
494
	 * preg_replace_callback hanlder
495
	 *
496
	 * replace image path
497
	 * @param array $match
498
	 *
499
	 * @return string changed result
500
	 */
501
	private function _replacePath($match)
502
	{
503
		//return origin conde when src value started '${'.
504
		if(preg_match('@^\${@', $match[1]))
505
		{
506
			return $match[0];
507
		}
508
509
		//return origin code when src value include variable.
510
		if(preg_match('@^[\'|"]\s*\.\s*\$@', $match[1]))
511
		{
512
			return $match[0];
513
		}
514
515
		$src = preg_replace('@^(\./)+@', '', trim($match[1]));
516
517
		$src = $this->web_path . $src;
518
		$src = str_replace('/./', '/', $src);
519
520
		// for backward compatibility
521
		$src = preg_replace('@/((?:[\w-]+/)+)\1@', '/\1', $src);
522
523
		while(($tmp = preg_replace('@[^/]+/\.\./@', '', $src, 1)) !== $src)
524
		{
525
			$src = $tmp;
526
		}
527
528
		return substr($match[0], 0, -strlen($match[1]) - 6) . "src=\"{$src}\"";
529
	}
530
531
	/**
532
	 * replace loop and cond template syntax
533
	 * @param string $buff
534
	 * @return string changed result
535
	 */
536
	private function _parseInline($buff)
537
	{
538
		if(!preg_match_all('/<([a-zA-Z]+\d?)(?:\s)/', $buff, $match))
539
		{
540
			return $buff;
541
		}
542
543
		$tags = array_diff(array_unique($match[1]), $this->skipTags);
544
545
		if(!count($tags))
546
		{
547
			return $buff;
548
		}
549
550
		$tags = '(?:' . implode('|', $tags) . ')';
551
		$split_regex = "@(<(?>/?{$tags})(?>[^<>\{\}\"']+|<!--.*?-->|{[^}]+}|\".*?\"|'.*?'|.)*?>)@s";
552
553
		$nodes = preg_split($split_regex, $buff, -1, PREG_SPLIT_DELIM_CAPTURE);
554
555
		// list of self closing tags
556
		$self_closing = array('area' => 1, 'base' => 1, 'basefont' => 1, 'br' => 1, 'hr' => 1, 'input' => 1, 'img' => 1, 'link' => 1, 'meta' => 1, 'param' => 1, 'frame' => 1, 'col' => 1);
557
558
		for($idx = 1, $node_len = count($nodes); $idx < $node_len; $idx+=2)
559
		{
560
			if(!($node = $nodes[$idx]))
561
			{
562
				continue;
563
			}
564
565
			if(preg_match_all('@\s(loop|cond)="([^"]+)"@', $node, $matches))
566
			{
567
				// this tag
568
				$tag = substr($node, 1, strpos($node, ' ') - 1);
569
570
				// if the vale of $closing is 0, it means 'skipping'
571
				$closing = 0;
572
573
				// process opening tag
574
				foreach($matches[1] as $n => $stmt)
575
				{
576
					$expr = $matches[2][$n];
577
					$expr = $this->_replaceVar($expr);
578
					$closing++;
579
580
					switch($stmt)
581
					{
582
						case 'cond':
583
							$nodes[$idx - 1] .= "<?php if({$expr}){ ?>";
584
							break;
585
						case 'loop':
586
							if(!preg_match('@^(?:(.+?)=>(.+?)(?:,(.+?))?|(.*?;.*?;.*?)|(.+?)\s*=\s*(.+?))$@', $expr, $expr_m))
587
							{
588
								break;
589
							}
590
							if($expr_m[1])
591
							{
592
								$expr_m[1] = trim($expr_m[1]);
593
								$expr_m[2] = trim($expr_m[2]);
594
								if($expr_m[3])
595
								{
596
									$expr_m[2] .= '=>' . trim($expr_m[3]);
597
								}
598
								$nodes[$idx - 1] .= "<?php if({$expr_m[1]}&&count({$expr_m[1]}))foreach({$expr_m[1]} as {$expr_m[2]}){ ?>";
599
							}
600
							elseif($expr_m[4])
601
							{
602
								$nodes[$idx - 1] .= "<?php for({$expr_m[4]}){ ?>";
603
							}
604
							elseif($expr_m[5])
605
							{
606
								$nodes[$idx - 1] .= "<?php while({$expr_m[5]}={$expr_m[6]}){ ?>";
607
							}
608
							break;
609
					}
610
				}
611
				$node = preg_replace('@\s(loop|cond)="([^"]+)"@', '', $node);
612
613
				// find closing tag
614
				$close_php = '<?php ' . str_repeat('}', $closing) . ' ?>';
615
				//  self closing tag
616
				if($node{1} == '!' || substr($node, -2, 1) == '/' || isset($self_closing[$tag]))
617
				{
618
					$nodes[$idx + 1] = $close_php . $nodes[$idx + 1];
619
				}
620
				else
621
				{
622
					$depth = 1;
623
					for($i = $idx + 2; $i < $node_len; $i+=2)
624
					{
625
						$nd = $nodes[$i];
626
						if(strpos($nd, $tag) === 1)
627
						{
628
							$depth++;
629
						}
630
						elseif(strpos($nd, '/' . $tag) === 1)
631
						{
632
							$depth--;
633
							if(!$depth)
634
							{
635
								$nodes[$i - 1] .= $nodes[$i] . $close_php;
636
								$nodes[$i] = '';
637
								break;
638
							}
639
						}
640
					}
641
				}
642
			}
643
644
			if(strpos($node, '|cond="') !== false)
645
			{
646
				$node = preg_replace('@(\s[-\w:]+(?:="[^"]+?")?)\|cond="(.+?)"@s', '<?php if($2){ ?>$1<?php } ?>', $node);
647
				$node = $this->_replaceVar($node);
648
			}
649
650
			if($nodes[$idx] != $node)
651
			{
652
				$nodes[$idx] = $node;
653
			}
654
		}
655
656
		$buff = implode('', $nodes);
657
658
		return $buff;
659
	}
660
661
	/**
662
	 * preg_replace_callback hanlder
663
	 * replace php code.
664
	 * @param array $m
665
	 * @return string changed result
666
	 */
667
	private function _parseResource($m)
668
	{
669
		$escape_option = 'noescape';
670
671
		if($this->safeguard)
672
		{
673
			$escape_option = 'autoescape';
674
		}
675
676
		// 템플릿에서 명시적으로 off이면 'noescape' 적용
677
		if ($this->config->autoescape === 'off') {
678
			$escape_option = 'noescape';
679
		}
680
681
		// {@ ... } or {$var} or {func(...)}
682
		if($m[1])
683
		{
684
			if(preg_match('@^(\w+)\(@', $m[1], $mm) && !function_exists($mm[1]))
685
			{
686
				return $m[0];
687
			}
688
			
689
			if($m[1]{0} == '@')
690
			{
691
				$m[1] = $this->_replaceVar(substr($m[1], 1));
692
				return "<?php {$m[1]} ?>";
693
			}
694
			else
695
			{
696
				// Get escape options.
697
				foreach ($this->ignoreEscape as $key => $value)
698
				{
699
					if($this->ignoreEscape[$key]($m))
700
					{
701
						$escape_option = 'noescape';
702
						break;
703
					}
704
				}
705
706
				// Separate filters from variable.
707
				if (preg_match('@^(.+?)(?<![|\s])((?:\|[a-z]{2}[a-z0-9_]+(?::.+)?)+)$@', $m[1], $mm))
708
				{
709
					$m[1] = $mm[1];
710
					$filters = array_map('trim', explode_with_escape('|', substr($mm[2], 1)));
711
				}
712
				else
713
				{
714
					$filters = array();
715
				}
716
717
				// Process the variable.
718
				$var = self::_replaceVar($m[1]);
719
720
				// Apply filters.
721
				foreach ($filters as $filter)
722
				{
723
					// Separate filter option from the filter name.
724
					if (preg_match('/^([a-z0-9_-]+):(.+)$/', $filter, $matches))
725
					{
726
						$filter = $matches[1];
727
						$filter_option = $matches[2];
728
						if (!self::_isVar($filter_option) && !preg_match("/^'.*'$/", $filter_option) && !preg_match('/^".*"$/', $filter_option))
729
						{
730
							$filter_option = "'" . escape_sqstr($filter_option) . "'";
731
						}
732
						else
733
						{
734
							$filter_option = self::_replaceVar($filter_option);
735
						}
736
					}
737
					else
738
					{
739
						$filter_option = null;
740
					}
741
742
					// Apply each filter.
743
					switch ($filter)
744
					{
745
						case 'auto':
746
						case 'autoescape':
747
						case 'escape':
748
						case 'noescape':
749
							$escape_option = $filter;
750
							break;
751
752
						case 'escapejs':
753
							$var = "escape_js({$var})";
754
							$escape_option = 'noescape';
755
							break;
756
757
						case 'json':
758
							$var = "json_encode({$var})";
759
							$escape_option = 'noescape';
760
							break;
761
762
						case 'strip':
763
						case 'strip_tags':
764
							$var = $filter_option ? "strip_tags({$var}, {$filter_option})" : "strip_tags({$var})";
765
							$escape_option = 'noescape';
766
							break;
767
768
						case 'trim':
769
							$var = "trim({$var})";
770
							break;
771
772
						case 'urlencode':
773
							$var = "rawurlencode({$var})";
774
							$escape_option = 'noescape';
775
							break;
776
777
						case 'lower':
778
							$var = "strtolower({$var})";
779
							break;
780
781
						case 'upper':
782
							$var = "strtoupper({$var})";
783
							break;
784
785
						case 'nl2br':
786
							$var = $this->_applyEscapeOption($var, $escape_option);
787
							$var = "nl2br({$var})";
788
							$escape_option = 'noescape';
789
							break;
790
791
						case 'join':
792
							$var = $filter_option ? "implode({$filter_option}, {$var})" : "implode(', ', {$var})";
793
							$escape_option = 'noescape';
794
							break;
795
796
						case 'date':
797
							$var = $filter_option ? "getDisplayDateTime(ztime({$var}), {$filter_option})" : "getDisplayDateTime(ztime({$var}), 'Y-m-d H:i:s')";
798
							$escape_option = 'noescape';
799
							break;
800
801
						case 'format':
802
						case 'number_format':
803
							$var = $filter_option ? "number_format({$var}, {$filter_option})" : "number_format({$var})";
804
							$escape_option = 'noescape';
805
							break;
806
807
						case 'link':
808
							$var = $this->_applyEscapeOption($var, 'autoescape');
809
							if ($filter_option)
0 ignored issues
show
Bug Best Practice introduced by
The expression $filter_option of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
810
							{
811
								$filter_option = $this->_applyEscapeOption($filter_option, 'autoescape');
812
								$var = "'<a href=\"' . {$filter_option} . '\">' . {$var} . '</a>'";
813
							}
814
							else
815
							{
816
								$var = "'<a href=\"' . {$var} . '\">' . {$var} . '</a>'";
817
							}
818
							$escape_option = 'noescape';
819
							break;
820
821
						default:
822
							$filter = escape_sqstr($filter);
823
							$var = "'INVALID FILTER ({$filter})'";
824
							$escape_option = 'noescape';
825
					}
826
				}
827
828
				// Apply the escape option and return.
829
				return '<?php echo ' . $this->_applyEscapeOption($var, $escape_option) . ' ?>';
830
			}
831
		}
832
833
		if($m[3])
834
		{
835
			$attr = array();
836
			if($m[5])
837
			{
838 View Code Duplication
				if(preg_match_all('@,(\w+)="([^"]+)"@', $m[6], $mm))
839
				{
840
					foreach($mm[1] as $idx => $name)
841
					{
842
						$attr[$name] = $mm[2][$idx];
843
					}
844
				}
845
				$attr['target'] = $m[5];
846
			}
847 View Code Duplication
			else
848
			{
849
				if(!preg_match_all('@ (\w+)="([^"]+)"@', $m[6], $mm))
850
				{
851
					return $m[0];
852
				}
853
				foreach($mm[1] as $idx => $name)
854
				{
855
					$attr[$name] = $mm[2][$idx];
856
				}
857
			}
858
859
			switch($m[3])
860
			{
861
				// <!--#include--> or <include ..>
862
				case 'include':
863
					if(!$this->file || !$attr['target'])
864
					{
865
						return '';
866
					}
867
868
					$pathinfo = pathinfo($attr['target']);
869
					$fileDir = $this->_getRelativeDir($pathinfo['dirname']);
870
871
					if(!$fileDir)
872
					{
873
						return '';
874
					}
875
876
					return "<?php \$__tpl=TemplateHandler::getInstance();echo \$__tpl->compile('{$fileDir}','{$pathinfo['basename']}') ?>";
877
				// <!--%load_js_plugin-->
878
				case 'load_js_plugin':
879
					$plugin = $this->_replaceVar($m[5]);
880
					$s = "<!--#JSPLUGIN:{$plugin}-->";
881
					if(strpos($plugin, '$__Context') === false)
882
					{
883
						$plugin = "'{$plugin}'";
884
					}
885
886
					$s .= "<?php Context::loadJavascriptPlugin({$plugin}); ?>";
887
					return $s;
888
				// <load ...> or <unload ...> or <!--%import ...--> or <!--%unload ...-->
889
				case 'import':
890
				case 'load':
891
				case 'unload':
892
					$metafile = '';
893
					$pathinfo = pathinfo($attr['target']);
894
					$doUnload = ($m[3] === 'unload');
895
					$isRemote = !!preg_match('@^(https?:)?//@i', $attr['target']);
896
897
					if(!$isRemote)
898
					{
899
						if(!preg_match('@^\.?/@', $attr['target']))
900
						{
901
							$attr['target'] = './' . $attr['target'];
902
						}
903
						if(substr($attr['target'], -5) == '/lang')
904
						{
905
							$pathinfo['dirname'] .= '/lang';
906
							$pathinfo['basename'] = '';
907
							$pathinfo['extension'] = 'xml';
908
						}
909
910
						$relativeDir = $this->_getRelativeDir($pathinfo['dirname']);
911
912
						$attr['target'] = $relativeDir . '/' . $pathinfo['basename'];
913
					}
914
915
					switch($pathinfo['extension'])
916
					{
917
						case 'xml':
918
							if($isRemote || $doUnload)
919
							{
920
								return '';
921
							}
922
							// language file?
923
							if($pathinfo['basename'] == 'lang.xml' || substr($pathinfo['dirname'], -5) == '/lang')
924
							{
925
								$result = "Context::loadLang('{$relativeDir}');";
0 ignored issues
show
Bug introduced by
The variable $relativeDir does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
926
							}
927
							else
928
							{
929
								$result = "require_once('./classes/xml/XmlJsFilter.class.php');\$__xmlFilter=new XmlJsFilter('{$relativeDir}','{$pathinfo['basename']}');\$__xmlFilter->compile();";
930
							}
931
							break;
932 View Code Duplication
						case 'js':
933
							if($doUnload)
934
							{
935
								$result = "Context::unloadFile('{$attr['target']}','{$attr['targetie']}');";
936
							}
937
							else
938
							{
939
								$metafile = $attr['target'];
940
								$result = "\$__tmp=array('{$attr['target']}','{$attr['type']}','{$attr['targetie']}','{$attr['index']}');Context::loadFile(\$__tmp);unset(\$__tmp);";
941
							}
942
							break;
943 View Code Duplication
						case 'css':
944
							if($doUnload)
945
							{
946
								$result = "Context::unloadFile('{$attr['target']}','{$attr['targetie']}','{$attr['media']}');";
947
							}
948
							else
949
							{
950
								$metafile = $attr['target'];
951
								$result = "\$__tmp=array('{$attr['target']}','{$attr['media']}','{$attr['targetie']}','{$attr['index']}');Context::loadFile(\$__tmp);unset(\$__tmp);";
952
							}
953
							break;
954
					}
955
956
					$result = "<?php {$result} ?>";
0 ignored issues
show
Bug introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
957
					if($metafile)
958
					{
959
						$result = "<!--#Meta:{$metafile}-->" . $result;
960
					}
961
962
					return $result;
963
				// <config ...>
964
				case 'config':
965
					$result = '';
966
					if(preg_match_all('@ (\w+)="([^"]+)"@', $m[6], $config_matches, PREG_SET_ORDER))
967
					{
968
						foreach($config_matches as $config_match)
969
						{
970
							$result .= "\$this->config->{$config_match[1]} = '" . trim(strtolower($config_match[2])) . "';";
971
						}
972
					}
973
					return "<?php {$result} ?>";
974
			}
975
		}
976
977
		// <[email protected]> such as <!--@if($cond)-->, <!--@else-->, <!--@end-->
978
		if($m[7])
979
		{
980
			$m[7] = substr($m[7], 1);
981 View Code Duplication
			if(!$m[7])
982
			{
983
				return '<?php ' . $this->_replaceVar($m[8]) . '{ ?>' . $m[9];
984
			}
985
			if(!preg_match('/^(?:((?:end)?(?:if|switch|for(?:each)?|while)|end)|(else(?:if)?)|(break@)?(case|default)|(break))$/', $m[7], $mm))
986
			{
987
				return '';
988
			}
989
			if($mm[1])
990
			{
991
				if($mm[1]{0} == 'e')
992
				{
993
					return '<?php } ?>' . $m[9];
994
				}
995
996
				$precheck = '';
997
				if($mm[1] == 'switch')
998
				{
999
					$m[9] = '';
1000
				}
1001
				elseif($mm[1] == 'foreach')
1002
				{
1003
					$var = preg_replace('/^\s*\(\s*(.+?) .*$/', '$1', $m[8]);
1004
					$precheck = "if({$var}&&count({$var}))";
1005
				}
1006
				return '<?php ' . $this->_replaceVar($precheck . $m[7] . $m[8]) . '{ ?>' . $m[9];
1007
			}
1008 View Code Duplication
			if($mm[2])
1009
			{
1010
				return "<?php }{$m[7]}" . $this->_replaceVar($m[8]) . "{ ?>" . $m[9];
1011
			}
1012
			if($mm[4])
1013
			{
1014
				return "<?php " . ($mm[3] ? 'break;' : '') . "{$m[7]} " . trim($m[8], '()') . ": ?>" . $m[9];
1015
			}
1016
			if($mm[5])
1017
			{
1018
				return "<?php break; ?>";
1019
			}
1020
			return '';
1021
		}
1022
		return $m[0];
1023
	}
1024
1025
	/**
1026
 	 * Apply escape option to an expression.
1027
 	 */
1028
 	private function _applyEscapeOption($str, $escape_option = 'noescape')
1029
 	{
1030
 		switch($escape_option)
1031
 		{
1032
 			case 'escape':
1033
 				return "escape({$str}, true)";
1034
 			case 'noescape':
1035
 				return "{$str}";
1036
 			case 'autoescape':
1037
 				return "escape({$str}, false)";
1038
 			case 'auto':
1039
 			default:
1040
 				return "(\$this->config->autoescape === 'on' ? escape({$str}, false) : {$str})";
1041
 		}
1042
 	}
1043
1044
	/**
1045
	 * change relative path
1046
	 * @param string $path
1047
	 * @return string
1048
	 */
1049
	function _getRelativeDir($path)
1050
	{
1051
		$_path = $path;
1052
1053
		$fileDir = strtr(realpath($this->path), '\\', '/');
1054
		if($path{0} != '/')
1055
		{
1056
			$path = strtr(realpath($fileDir . '/' . $path), '\\', '/');
1057
		}
1058
1059
		// for backward compatibility
1060
		if(!$path)
1061
		{
1062
			$dirs = explode('/', $fileDir);
1063
			$paths = explode('/', $_path);
1064
			$idx = array_search($paths[0], $dirs);
1065
1066
			if($idx !== false)
1067
			{
1068
				while($dirs[$idx] && $dirs[$idx] === $paths[0])
1069
				{
1070
					array_splice($dirs, $idx, 1);
1071
					array_shift($paths);
1072
				}
1073
				$path = strtr(realpath($fileDir . '/' . implode('/', $paths)), '\\', '/');
1074
			}
1075
		}
1076
1077
		$path = preg_replace('/^' . preg_quote(_XE_PATH_, '/') . '/', '', $path);
1078
1079
		return $path;
1080
	}
1081
1082
	/**
1083
 	 * Check if a string seems to contain a variable.
1084
 	 * 
1085
 	 * @param string $str
1086
 	 * @return bool
1087
 	 */
1088
 	private static function _isVar($str)
1089
 	{
1090
 		return preg_match('@(?<!::|\\\\|(?<!eval\()\')\$([a-z_][a-z0-9_]*)@i', $str) ? true : false;
1091
 	}
1092
1093
	/**
1094
	 * Replace PHP variables of $ character
1095
	 * @param string $php
1096
	 * @return string $__Context->varname
1097
	 */
1098
	function _replaceVar($php)
1099
	{
1100
		if(!strlen($php))
1101
		{
1102
			return '';
1103
		}
1104
		return preg_replace('@(?<!::|\\\\|(?<!eval\()\')\$([a-z]|_[a-z0-9])@i', '\$__Context->$1', $php);
1105
	}
1106
1107
	function isSafeguard()
1108
	{
1109
		if ($this->dbinfo->safeguard === 'Y') return true;
1110
1111
		$absPath = str_replace(_XE_PATH_, '', $this->path);
1112
		$modules = '(addon|admin|adminlogging|autoinstall|board|comment|communication|counter|document|editor|file|importer|install|integration_search|krzip|layout|member|menu|message|module|page|point|poll|rss|seo|session|spamfilter|syndication|tag|trash|widget)';
1113
1114
		// admin, common layout
1115
		if(preg_match('/^(\.\/)?(modules\/' . $modules . '|common)\/tpl\//', $absPath))
1116
		{
1117
			return true;
1118
		}
1119
1120
		return false;
1121
	}
1122
1123
	public function setSafeguard($val = true)
1124
	{
1125
		$this->safeguard = $val;
1126
	}
1127
}
1128
/* End of File: TemplateHandler.class.php */
1129
/* Location: ./classes/template/TemplateHandler.class.php */
1130