Mercurial > SimpleWebPresenter
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/InputParser.inc.php Sun Jan 22 19:22:00 2023 +0100 @@ -0,0 +1,368 @@ +<?php +/// @cond +$baseDir = dirname(__FILE__); +$cache = ScriptIncludeCache::instance(__FILE__); +$cache->includeOnce('Page.inc.php', dirname(__FILE__)); +/// @endcond + +/** + * Functionality for translating an XML configuration document into a webpage + */ +class InputParser extends Page +{ + private $options; + private $master; + + /** + * Constructs a new InputParser object + * + * @param $name name of file to read configuration from + * + * @param $masterCache CacheTimeCheck cache object to use as parent + * for this inputParsercache + */ + function __construct($name, $masterCache) { + $this->master = new DOMDocument(); + $cache = new CacheTimeCheck($name); + $cache->addParent($masterCache); + parent::setCache($cache); + $this->master->load($name); + + $this->options = new Options($this->master); + $this->options->setCache($cache); + $base=basePath(); + $base=$_SERVER['DOCUMENT_ROOT']; + $this->options->setBasePath($base); + $this->options->setCacheable(true); + + $this->options->setUrlParams(array('name', 'lang')); + + if(array_key_exists('lang', $_GET) && $_GET['lang']) { + $this->options->setLang($_GET['lang']); + } + else { + if (count($this->options->getAcceptedLanguages()) > 1) + $this->addVariant('Accept-Language'); + $this->options->setLang($this->options->getDefaultLang()); + } + + if(array_key_exists('name', $_GET) && $_GET['name']) { + $this->options->setName($_GET['name']); + } + else { + $pathToAnalyze=$_SERVER['PATH_TRANSLATED']; + $prefix=$_SERVER['SCRIPT_FILENAME']; + if (substr($pathToAnalyze, 0, strlen($prefix)) == $prefix) { + $pathToAnalyze = substr($pathToAnalyze, strlen($prefix)); + } + preg_match('/\/([^\/]*)$/', $pathToAnalyze, $groups); + if ($groups[1]) { + $this->options->setName($groups[1]); + } + } + + + $params = $this->master->getElementsByTagName("param"); + + foreach ($params as $param) { + if ($param->getAttribute("type") == "input") { + $doc = self::getInput($this->master, $param, $this->options); + + $parent = $param->parentNode; + foreach ($doc->firstChild->childNodes as $child) { + $clonedChild = $this->master->importNode($child, true); + $parent->insertBefore($clonedChild, $param); + } + $parent->removeChild($param); + } + } + $this->master = self::getFiles($this->master, $this->options); + self::removeCommentsFromDOM($this->master); + $cache->setMaxAge(0); + } + + /** + * Removes all comments from the DOM + * + * @param $dom A DOMDocument for processing + */ + static function removeCommentsFromDOM($dom) + { + $xpath = new DOMXPath($dom); + foreach ($xpath->query('//comment()') as $comment) { + $comment->parentNode->removeChild($comment); + } + } + + function cacheCheck() + { + return $this->options->getCacheable(); + } + + /** + * Generate an appropriate response for this page, eg. 302 NOT + * MODIFIED or the actual page + */ + function generateContent() + { + //We may need to set and check the contenttype and replace + //saveHTML with saveXML + $retVal = new PageContent(options::replacePlaceholders($this->master->saveXML())); + $retVal->setHeader('Content-Language', $this->options->getLang()); + return $retVal; + } + + /** + * Extracts data from a @<param@> tag. + * + * @param $param the param tag + * + * @return if the type is array, return an array, otherwise return a + * scalar + */ + static function getParam($param) + { + $param_type = $param->getAttribute("type"); + $param_value; + if (! $param_type) + $param_type = "scalar"; + + if($param_type == "scalar") { + $param_subst = $param->getAttribute("subst"); + $param_value = $param->getAttribute("value"); + if ($param_subst) { + /* + $param_value=preg_replace("/name/", $name, $param_subst); + $param_value=preg_replace('/lang/', $lang, $param_value); + */ + } + } + elseif($param_type == "array") { + $params = $param->getElementsByTagName("param"); + $param_value = array(); + foreach ($param->childNodes as $param) { + if ($param->nodeType == XML_ELEMENT_NODE) { + array_push($param_value, self::getParam($param)); + } + } + } + else { + throw new UnexpectedValueException("Unknown parameter type '$param_type'"); + } + return $param_value; + } + + /** + * This is the last processing stage for generating a file. + * + * @param $doc the document to be worked upon + * @param $options an Options object for this file. + * + * @return This is the same as the input document, fully processed + */ + static function getFiles($doc, $options) { + $lang = $options->getLang(); + $conf = $options->getName(); + + $toRemove = array(); + + $topLevelTags = $doc->getElementsByTagName("toplevel"); + foreach ($topLevelTags as $topLevel) { + $topLevel->parentNode->removeChild($topLevel); + } + + $valueDict = array(); + $fragments = array(); + $setters = $doc->getElementsByTagName("set"); + foreach ($setters as $setTag) { + $key = $setTag->getAttribute("id"); + $type = $setTag->getAttribute("type"); + if ($type == "fragment") { + $fragments[$key] = $setTag; + } + else { + $value = $setTag->getAttribute("value"); + if ($key && $value) { + $valueDict[$key] = $value; + } + } + //We need to iterate in the opposite direction when removing, + //so best shifting. + array_unshift($toRemove, $setTag); + } + + $params = $doc->getElementsByTagName("param"); + foreach ($params as $param) { + if ($param->getAttribute("type")=="input_config") { + $id = $param->getAttribute("id"); + if (array_key_exists($id, $valueDict)) { + $value = $valueDict[$id]; + $tmp = new DOMDocument(); + + $tmp->loadXml("<xml>${value}</xml>"); + $parent = $param->parentNode; + $parent->insertBefore(new DOMText($tmp->textContent), $param); + //We need to iterate in the opposite direction when removing, + //so best shifting. + array_unshift($toRemove, $param); + } + elseif (array_key_exists($id, $fragments)) { + $fragment = $fragments[$id]; + + $cloneFragment = $fragment->cloneNode(true); + $insNode = $param; + for ($i = $cloneFragment->childNodes->length - 1; $i >= 0; $i--) { + $child = $cloneFragment->childNodes->item($i); + $child = $child->parentNode->removeChild($child); + $insNode = $insNode->parentNode->insertBefore($child, $insNode); + } + + //We need to iterate in the opposite direction when removing, + //so best shifting. + array_unshift($toRemove, $param); + } + } + } + + foreach($toRemove as $param) { + $parent = $param->parentNode; + $parent->removeChild($param); + } + + $body = getElementByTagName($doc,"html"); + $files = $body->getElementsByTagName("file"); + + $toRemove = array(); + + foreach ($files as $file) { + $script = $file->getAttribute("script"); + if ($script) { + $options->setCacheable(false); + $src=""; + $cwd = getcwd(); + + $matches=array(); + preg_match('/(.*\/)/', $script, $matches); + $dirname=$matches[0]; + preg_match('/([^\/]*)$/', $script, $matches); + $filename=$matches[0]; + chdir("${lang}/${dirname}"); + $pipe=popen("php ${filename}","r"); + $file_content = stream_get_contents($pipe); + chdir("${cwd}"); + } + else { + $src = $file->getAttribute("src"); + $fname = $options->getBasePath() . "/${lang}/${src}"; + if (!file_exists($fname) ) { + $fname = $options->getBasePath() . "/common/${src}"; + } + $file_content = $options->getCache()->loadFile($fname); + } + if(floatval($file_content)<0) { + errorPage("Resource not found '${lang}/${src}'"); + } + + $filters = $file->getElementsByTagName("filter"); + foreach($filters as $filter) { + $func = $filter->getAttribute("function"); + $params = $filter->getElementsByTagName("param"); + $callString = "\$file_content = ${func}(\$file_content, \$options"; + $param_values = array(); + $i = 0; + foreach ($filter->childNodes as $param) { + if ($param->nodeType == XML_ELEMENT_NODE) + { + $param_value[$i] = self::getParam($param); + $callString .= ",\$param_value[$i]"; + $i++; + } + } + $callString .= ");"; + eval($callString); + } + $ndoc = $doc->createDocumentFragment(); + + $parent = $file->parentNode; + + $ndoc->appendXML($file_content); + $parent->insertBefore($ndoc, $file); + + //We need to iterate in the opposite direction when removing, + //so best shifting. + array_unshift($toRemove, $file); + } + foreach($toRemove as $param) { + $parent = $param->parentNode; + $parent->removeChild($param); + } + + return $doc; + } + + /** + * Follows all include directives recursively for the specified + * $param an generates an xml file. + * + * This function may be used to generate a file which has all the + * necessary information to determine wether or not we may cache. + * + * @param $master The master document to be processed + * @param $param the input tag to resolve + * @param $options the options object for this file + */ + function getInput($master, $param, $options) + { + $lang = $options->getLang(); + $name = $param->getAttribute("id"); + $conf = $options->getName(); + if (!$conf) + $conf = $param->getAttribute("default"); + + $confFile = $options->getBasePath() . "/${lang}/${conf}.xml"; + if (! file_exists($confFile) ) { + $confFile = $options->getBasePath() . "/common/${conf}.xml"; + } + + $options->getCache()->cache_time($confFile); + $doc = new DOMDocument(); + $doc->load($confFile); + + $toplevel = $doc->getElementsByTagName("toplevel"); + + if(! $toplevel->length) { + errorPage("Resource '${conf}' is not available", 500); + } + + $includes = $doc->getElementsByTagName("include"); + $recurse = 0; + + while($includes->length > 0) { + if(++$recurse > MAX_RECURSE) { + errorPage('Recursion limit exceeded', 500); + } + foreach ($includes as $include) { + $src = $include->getAttribute("src"); + $subdoc = new DOMDocument(); + $subfile = $options->getBasePath() . "/${lang}/${src}"; + if (! file_exists($subfile) ) { + $subfile = $options->getBasePath() . "/common/${src}"; + } + $subdoc->load("$subfile"); + $options->getCache()->cache_time($subfile); + $parent = $include->parentNode; + $xml = getElementByTagName($subdoc,"xml"); + foreach($xml->childNodes as $child) { + $text = $subdoc->saveHTML($child); + $clonedChild = $doc->importNode($child,true); + $parent->insertBefore($clonedChild,$include); + } + $parent->removeChild($include); + } + $includes = $doc->getElementsByTagName("include"); + } + + return $doc; + } +} +?>
