Mercurial > SimpleWebPresenter
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 ?> |
