1<?php
2/**
3 * Loads various functions used in parsing XML (mostly for extensions).
4 *
5 * @copyright (C) 2008-2012 PunBB, partially based on code (C) 2008-2009 FluxBB.org
6 * @license http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
7 * @package PunBB
8 */
9
10
11// Make sure no one attempts to run this script "directly"
12if (!defined('FORUM'))
13	exit;
14
15
16//
17// Parse XML data into an array
18//
19function xml_to_array($raw_xml)
20{
21    $multi_key = array();
22    $multi_key2 = array();
23	$xml_parser = xml_parser_create();
24	xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0);
25	xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0);
26	xml_parse_into_struct($xml_parser, $raw_xml, $vals);
27	xml_parser_free($xml_parser);
28	unset($xml_parser);
29
30	$_tmp = '';
31	foreach ($vals as $xml_elem)
32	{
33		$x_tag = $xml_elem['tag'];
34		$x_level = $xml_elem['level'];
35		$x_type = $xml_elem['type'];
36
37		if ($x_level != 1 && $x_type == 'close')
38		{
39			if (isset($multi_key[$x_tag][$x_level]))
40				$multi_key[$x_tag][$x_level] = 1;
41			else
42				$multi_key[$x_tag][$x_level] = 0;
43		}
44
45		if ($x_level != 1 && $x_type == 'complete')
46		{
47			if ($_tmp == $x_tag)
48				$multi_key[$x_tag][$x_level] = 1;
49
50			$_tmp = $x_tag;
51		}
52	}
53
54	foreach ($vals as $xml_elem)
55	{
56		$x_tag = $xml_elem['tag'];
57		$x_level = $xml_elem['level'];
58		$x_type = $xml_elem['type'];
59
60		if ($x_type == 'open')
61			$level[$x_level] = $x_tag;
62
63		$start_level = 1;
64		$php_stmt = '$xml_array';
65		if ($x_type == 'close' && $x_level != 1)
66			$multi_key[$x_tag][$x_level]++;
67
68		while ($start_level < $x_level)
69		{
70			$php_stmt .= '[$level['.$start_level.']]';
71			if (isset($multi_key[$level[$start_level]][$start_level]) && $multi_key[$level[$start_level]][$start_level])
72				$php_stmt .= '['.($multi_key[$level[$start_level]][$start_level]-1).']';
73
74			++$start_level;
75		}
76
77		$add = '';
78		if (isset($multi_key[$x_tag][$x_level]) && $multi_key[$x_tag][$x_level] && ($x_type == 'open' || $x_type == 'complete'))
79		{
80			if (!isset($multi_key2[$x_tag][$x_level]))
81				$multi_key2[$x_tag][$x_level] = 0;
82			else
83				$multi_key2[$x_tag][$x_level]++;
84
85			$add = '['.$multi_key2[$x_tag][$x_level].']';
86		}
87
88		if (isset($xml_elem['value']) && forum_trim($xml_elem['value']) != '' && !array_key_exists('attributes', $xml_elem))
89		{
90			if ($x_type == 'open')
91				$php_stmt_main = $php_stmt.'[$x_type]'.$add.'[\'content\'] = $xml_elem[\'value\'];';
92			else
93				$php_stmt_main = $php_stmt.'[$x_tag]'.$add.' = $xml_elem[\'value\'];';
94
95			eval($php_stmt_main);
96		}
97
98		if (array_key_exists('attributes', $xml_elem))
99		{
100			if (isset($xml_elem['value']))
101			{
102				$php_stmt_main = $php_stmt.'[$x_tag]'.$add.'[\'content\'] = $xml_elem[\'value\'];';
103				eval($php_stmt_main);
104			}
105
106			foreach ($xml_elem['attributes'] as $key=>$value)
107			{
108				$php_stmt_att=$php_stmt.'[$x_tag]'.$add.'[\'attributes\'][$key] = $value;';
109				eval($php_stmt_att);
110			}
111		}
112	}
113
114	if (isset($xml_array))
115	{
116		// Make sure there's an array of notes (even if there is only one)
117		if (isset($xml_array['extension']['note']))
118		{
119			if (!is_array(current($xml_array['extension']['note'])))
120				$xml_array['extension']['note'] = array($xml_array['extension']['note']);
121		}
122		else
123			$xml_array['extension']['note'] = array();
124
125		// Make sure there's an array of hooks (even if there is only one)
126		if (isset($xml_array['extension']['hooks']) && isset($xml_array['extension']['hooks']['hook']))
127		{
128			if (!is_array(current($xml_array['extension']['hooks']['hook'])))
129				$xml_array['extension']['hooks']['hook'] = array($xml_array['extension']['hooks']['hook']);
130		}
131	}
132
133	return isset($xml_array) ? $xml_array : array();
134}
135
136
137//
138// Validate the syntax of an extension manifest file
139//
140function validate_manifest($xml_array, $folder_name)
141{
142	global $lang_admin_ext, $forum_config;
143
144	$errors = array();
145
146	$return = ($hook = get_hook('xm_fn_validate_manifest_start')) ? eval($hook) : null;
147	if ($return !== null)
148		return;
149
150	if (!isset($xml_array['extension']) || !is_array($xml_array['extension']))
151		$errors[] = $lang_admin_ext['extension root error'];
152	else
153	{
154		$ext = $xml_array['extension'];
155		if (!isset($ext['attributes']['engine']))
156			$errors[] = $lang_admin_ext['extension/engine error'];
157		else if ($ext['attributes']['engine'] != '1.0')
158			$errors[] = $lang_admin_ext['extension/engine error2'];
159
160		if (!isset($ext['id']) || $ext['id'] == '')
161			$errors[] = $lang_admin_ext['extension/id error'];
162		else if ($ext['id'] != $folder_name)
163			$errors[] = $lang_admin_ext['extension/id error2'];
164
165		if (!isset($ext['title']) || $ext['title'] == '')
166			$errors[] = $lang_admin_ext['extension/title error'];
167		if (!isset($ext['version']) || $ext['version'] == '' || preg_match('/[^a-z0-9\- \.]+/i', $ext['version']))
168			$errors[] = $lang_admin_ext['extension/version error'];
169		if (!isset($ext['description']) || $ext['description'] == '')
170			$errors[] = $lang_admin_ext['extension/description error'];
171		if (!isset($ext['author']) || $ext['author'] == '')
172			$errors[] = $lang_admin_ext['extension/author error'];
173		if (!isset($ext['minversion']) || $ext['minversion'] == '')
174			$errors[] = $lang_admin_ext['extension/minversion error'];
175		if (isset($ext['minversion']) && version_compare(clean_version($forum_config['o_cur_version']), clean_version($ext['minversion']), '<'))
176			$errors[] = sprintf($lang_admin_ext['extension/minversion error2'], $ext['minversion']);
177		if (!isset($ext['maxtestedon']) || $ext['maxtestedon'] == '')
178			$errors[] = $lang_admin_ext['extension/maxtestedon error'];
179
180		if (isset($ext['note']))
181		{
182			foreach ($ext['note'] as $note)
183			{
184				if (!isset($note['content']) || $note['content'] == '')
185					$errors[] = $lang_admin_ext['extension/note error'];
186				if (!isset($note['attributes']['type']) || $note['attributes']['type'] == '')
187					$errors[] = $lang_admin_ext['extension/note error2'];
188			}
189		}
190
191		if (isset($ext['hooks']) && is_array($ext['hooks']))
192		{
193			if (!isset($ext['hooks']['hook']) || !is_array($ext['hooks']['hook']))
194				$errors[] = $lang_admin_ext['extension/hooks/hook error'];
195			else
196			{
197				foreach ($ext['hooks']['hook'] as $hook)
198				{
199					if (!isset($hook['content']) || $hook['content'] == '')
200						$errors[] = $lang_admin_ext['extension/hooks/hook error'];
201					if (!isset($hook['attributes']['id']) || $hook['attributes']['id'] == '')
202						$errors[] = $lang_admin_ext['extension/hooks/hook error2'];
203					if (isset($hook['attributes']['priority']) && (!ctype_digit($hook['attributes']['priority']) || $hook['attributes']['priority'] < 0 || $hook['attributes']['priority'] > 10))
204						$errors[] = $lang_admin_ext['extension/hooks/hook error3'];
205
206					$tokenized_hook = token_get_all('<?php '.$hook['content']);
207					$last_element = array_pop($tokenized_hook);
208					if (is_array($last_element) && $last_element[0] == T_INLINE_HTML)
209						$errors[] = $lang_admin_ext['extension/hooks/hook error4'];
210				}
211			}
212		}
213	}
214
215	($hook = get_hook('xm_fn_validate_manifest_end')) ? eval($hook) : null;
216
217	return $errors;
218}
219
220define('FORUM_XML_FUNCTIONS_LOADED', 1);
221