comparison InputParser.inc.php @ 134:b6b4a58c7625

Using .inc.php rather than just .inc for include files.
author Tom Fredrik Blenning <bfg@bfgconsult.no>
date Sun, 22 Jan 2023 19:22:00 +0100
parents InputParser.inc@ee5f98a0bc93
children
comparison
equal deleted inserted replaced
133:00255ca89459 134:b6b4a58c7625
1 <?php
2 /// @cond
3 $baseDir = dirname(__FILE__);
4 $cache = ScriptIncludeCache::instance(__FILE__);
5 $cache->includeOnce('Page.inc.php', dirname(__FILE__));
6 /// @endcond
7
8 /**
9 * Functionality for translating an XML configuration document into a webpage
10 */
11 class InputParser extends Page
12 {
13 private $options;
14 private $master;
15
16 /**
17 * Constructs a new InputParser object
18 *
19 * @param $name name of file to read configuration from
20 *
21 * @param $masterCache CacheTimeCheck cache object to use as parent
22 * for this inputParsercache
23 */
24 function __construct($name, $masterCache) {
25 $this->master = new DOMDocument();
26 $cache = new CacheTimeCheck($name);
27 $cache->addParent($masterCache);
28 parent::setCache($cache);
29 $this->master->load($name);
30
31 $this->options = new Options($this->master);
32 $this->options->setCache($cache);
33 $base=basePath();
34 $base=$_SERVER['DOCUMENT_ROOT'];
35 $this->options->setBasePath($base);
36 $this->options->setCacheable(true);
37
38 $this->options->setUrlParams(array('name', 'lang'));
39
40 if(array_key_exists('lang', $_GET) && $_GET['lang']) {
41 $this->options->setLang($_GET['lang']);
42 }
43 else {
44 if (count($this->options->getAcceptedLanguages()) > 1)
45 $this->addVariant('Accept-Language');
46 $this->options->setLang($this->options->getDefaultLang());
47 }
48
49 if(array_key_exists('name', $_GET) && $_GET['name']) {
50 $this->options->setName($_GET['name']);
51 }
52 else {
53 $pathToAnalyze=$_SERVER['PATH_TRANSLATED'];
54 $prefix=$_SERVER['SCRIPT_FILENAME'];
55 if (substr($pathToAnalyze, 0, strlen($prefix)) == $prefix) {
56 $pathToAnalyze = substr($pathToAnalyze, strlen($prefix));
57 }
58 preg_match('/\/([^\/]*)$/', $pathToAnalyze, $groups);
59 if ($groups[1]) {
60 $this->options->setName($groups[1]);
61 }
62 }
63
64
65 $params = $this->master->getElementsByTagName("param");
66
67 foreach ($params as $param) {
68 if ($param->getAttribute("type") == "input") {
69 $doc = self::getInput($this->master, $param, $this->options);
70
71 $parent = $param->parentNode;
72 foreach ($doc->firstChild->childNodes as $child) {
73 $clonedChild = $this->master->importNode($child, true);
74 $parent->insertBefore($clonedChild, $param);
75 }
76 $parent->removeChild($param);
77 }
78 }
79 $this->master = self::getFiles($this->master, $this->options);
80 self::removeCommentsFromDOM($this->master);
81 $cache->setMaxAge(0);
82 }
83
84 /**
85 * Removes all comments from the DOM
86 *
87 * @param $dom A DOMDocument for processing
88 */
89 static function removeCommentsFromDOM($dom)
90 {
91 $xpath = new DOMXPath($dom);
92 foreach ($xpath->query('//comment()') as $comment) {
93 $comment->parentNode->removeChild($comment);
94 }
95 }
96
97 function cacheCheck()
98 {
99 return $this->options->getCacheable();
100 }
101
102 /**
103 * Generate an appropriate response for this page, eg. 302 NOT
104 * MODIFIED or the actual page
105 */
106 function generateContent()
107 {
108 //We may need to set and check the contenttype and replace
109 //saveHTML with saveXML
110 $retVal = new PageContent(options::replacePlaceholders($this->master->saveXML()));
111 $retVal->setHeader('Content-Language', $this->options->getLang());
112 return $retVal;
113 }
114
115 /**
116 * Extracts data from a @<param@> tag.
117 *
118 * @param $param the param tag
119 *
120 * @return if the type is array, return an array, otherwise return a
121 * scalar
122 */
123 static function getParam($param)
124 {
125 $param_type = $param->getAttribute("type");
126 $param_value;
127 if (! $param_type)
128 $param_type = "scalar";
129
130 if($param_type == "scalar") {
131 $param_subst = $param->getAttribute("subst");
132 $param_value = $param->getAttribute("value");
133 if ($param_subst) {
134 /*
135 $param_value=preg_replace("/name/", $name, $param_subst);
136 $param_value=preg_replace('/lang/', $lang, $param_value);
137 */
138 }
139 }
140 elseif($param_type == "array") {
141 $params = $param->getElementsByTagName("param");
142 $param_value = array();
143 foreach ($param->childNodes as $param) {
144 if ($param->nodeType == XML_ELEMENT_NODE) {
145 array_push($param_value, self::getParam($param));
146 }
147 }
148 }
149 else {
150 throw new UnexpectedValueException("Unknown parameter type '$param_type'");
151 }
152 return $param_value;
153 }
154
155 /**
156 * This is the last processing stage for generating a file.
157 *
158 * @param $doc the document to be worked upon
159 * @param $options an Options object for this file.
160 *
161 * @return This is the same as the input document, fully processed
162 */
163 static function getFiles($doc, $options) {
164 $lang = $options->getLang();
165 $conf = $options->getName();
166
167 $toRemove = array();
168
169 $topLevelTags = $doc->getElementsByTagName("toplevel");
170 foreach ($topLevelTags as $topLevel) {
171 $topLevel->parentNode->removeChild($topLevel);
172 }
173
174 $valueDict = array();
175 $fragments = array();
176 $setters = $doc->getElementsByTagName("set");
177 foreach ($setters as $setTag) {
178 $key = $setTag->getAttribute("id");
179 $type = $setTag->getAttribute("type");
180 if ($type == "fragment") {
181 $fragments[$key] = $setTag;
182 }
183 else {
184 $value = $setTag->getAttribute("value");
185 if ($key && $value) {
186 $valueDict[$key] = $value;
187 }
188 }
189 //We need to iterate in the opposite direction when removing,
190 //so best shifting.
191 array_unshift($toRemove, $setTag);
192 }
193
194 $params = $doc->getElementsByTagName("param");
195 foreach ($params as $param) {
196 if ($param->getAttribute("type")=="input_config") {
197 $id = $param->getAttribute("id");
198 if (array_key_exists($id, $valueDict)) {
199 $value = $valueDict[$id];
200 $tmp = new DOMDocument();
201
202 $tmp->loadXml("<xml>${value}</xml>");
203 $parent = $param->parentNode;
204 $parent->insertBefore(new DOMText($tmp->textContent), $param);
205 //We need to iterate in the opposite direction when removing,
206 //so best shifting.
207 array_unshift($toRemove, $param);
208 }
209 elseif (array_key_exists($id, $fragments)) {
210 $fragment = $fragments[$id];
211
212 $cloneFragment = $fragment->cloneNode(true);
213 $insNode = $param;
214 for ($i = $cloneFragment->childNodes->length - 1; $i >= 0; $i--) {
215 $child = $cloneFragment->childNodes->item($i);
216 $child = $child->parentNode->removeChild($child);
217 $insNode = $insNode->parentNode->insertBefore($child, $insNode);
218 }
219
220 //We need to iterate in the opposite direction when removing,
221 //so best shifting.
222 array_unshift($toRemove, $param);
223 }
224 }
225 }
226
227 foreach($toRemove as $param) {
228 $parent = $param->parentNode;
229 $parent->removeChild($param);
230 }
231
232 $body = getElementByTagName($doc,"html");
233 $files = $body->getElementsByTagName("file");
234
235 $toRemove = array();
236
237 foreach ($files as $file) {
238 $script = $file->getAttribute("script");
239 if ($script) {
240 $options->setCacheable(false);
241 $src="";
242 $cwd = getcwd();
243
244 $matches=array();
245 preg_match('/(.*\/)/', $script, $matches);
246 $dirname=$matches[0];
247 preg_match('/([^\/]*)$/', $script, $matches);
248 $filename=$matches[0];
249 chdir("${lang}/${dirname}");
250 $pipe=popen("php ${filename}","r");
251 $file_content = stream_get_contents($pipe);
252 chdir("${cwd}");
253 }
254 else {
255 $src = $file->getAttribute("src");
256 $fname = $options->getBasePath() . "/${lang}/${src}";
257 if (!file_exists($fname) ) {
258 $fname = $options->getBasePath() . "/common/${src}";
259 }
260 $file_content = $options->getCache()->loadFile($fname);
261 }
262 if(floatval($file_content)<0) {
263 errorPage("Resource not found '${lang}/${src}'");
264 }
265
266 $filters = $file->getElementsByTagName("filter");
267 foreach($filters as $filter) {
268 $func = $filter->getAttribute("function");
269 $params = $filter->getElementsByTagName("param");
270 $callString = "\$file_content = ${func}(\$file_content, \$options";
271 $param_values = array();
272 $i = 0;
273 foreach ($filter->childNodes as $param) {
274 if ($param->nodeType == XML_ELEMENT_NODE)
275 {
276 $param_value[$i] = self::getParam($param);
277 $callString .= ",\$param_value[$i]";
278 $i++;
279 }
280 }
281 $callString .= ");";
282 eval($callString);
283 }
284 $ndoc = $doc->createDocumentFragment();
285
286 $parent = $file->parentNode;
287
288 $ndoc->appendXML($file_content);
289 $parent->insertBefore($ndoc, $file);
290
291 //We need to iterate in the opposite direction when removing,
292 //so best shifting.
293 array_unshift($toRemove, $file);
294 }
295 foreach($toRemove as $param) {
296 $parent = $param->parentNode;
297 $parent->removeChild($param);
298 }
299
300 return $doc;
301 }
302
303 /**
304 * Follows all include directives recursively for the specified
305 * $param an generates an xml file.
306 *
307 * This function may be used to generate a file which has all the
308 * necessary information to determine wether or not we may cache.
309 *
310 * @param $master The master document to be processed
311 * @param $param the input tag to resolve
312 * @param $options the options object for this file
313 */
314 function getInput($master, $param, $options)
315 {
316 $lang = $options->getLang();
317 $name = $param->getAttribute("id");
318 $conf = $options->getName();
319 if (!$conf)
320 $conf = $param->getAttribute("default");
321
322 $confFile = $options->getBasePath() . "/${lang}/${conf}.xml";
323 if (! file_exists($confFile) ) {
324 $confFile = $options->getBasePath() . "/common/${conf}.xml";
325 }
326
327 $options->getCache()->cache_time($confFile);
328 $doc = new DOMDocument();
329 $doc->load($confFile);
330
331 $toplevel = $doc->getElementsByTagName("toplevel");
332
333 if(! $toplevel->length) {
334 errorPage("Resource '${conf}' is not available", 500);
335 }
336
337 $includes = $doc->getElementsByTagName("include");
338 $recurse = 0;
339
340 while($includes->length > 0) {
341 if(++$recurse > MAX_RECURSE) {
342 errorPage('Recursion limit exceeded', 500);
343 }
344 foreach ($includes as $include) {
345 $src = $include->getAttribute("src");
346 $subdoc = new DOMDocument();
347 $subfile = $options->getBasePath() . "/${lang}/${src}";
348 if (! file_exists($subfile) ) {
349 $subfile = $options->getBasePath() . "/common/${src}";
350 }
351 $subdoc->load("$subfile");
352 $options->getCache()->cache_time($subfile);
353 $parent = $include->parentNode;
354 $xml = getElementByTagName($subdoc,"xml");
355 foreach($xml->childNodes as $child) {
356 $text = $subdoc->saveHTML($child);
357 $clonedChild = $doc->importNode($child,true);
358 $parent->insertBefore($clonedChild,$include);
359 }
360 $parent->removeChild($include);
361 }
362 $includes = $doc->getElementsByTagName("include");
363 }
364
365 return $doc;
366 }
367 }
368 ?>