private function replace_www($template, $document, $args = array()) { foreach ($document->query('//www:*') as $node) { $nested = null; switch ($node->name()) { case 'www:template': $nested = $this->render_template($template->get($node['@name'])); break; case 'www:xslt': $args = $node->attribute('args'); if ($node->attribute('cache') !== 'true') { $nested = $this->render_xslt($template, $node['@xsl'], $node['@xml'], $args ? args::decode($args) : array()); } else { $cache_args = $node->attribute('cache-args') ? $node->attribute('cache-args') : array(); $cache_lifetime = $node->attribute('cache-lifetime'); is_null($cache_lifetime) or is_numeric($cache_lifetime) or runtime_error('Cache lifetime should be numeric: ' . $cache_lifetime); $cache_args = args::decode($cache_args); $filename = cache_location . md5($node['@xsl'] . $node['@xml'] . ($args ? $args : '')) . '.xml'; if (!fs::exists($filename) || $cache_lifetime && $cache_lifetime > time() - fs::modification($filename)) { fs::write($filename, $this->render_xslt($template, $node['@xsl'], $node['@xml'], $args ? args::decode($args) : array())->render(false)); } $fragment = fs::checked_read($filename); if (!empty($cache_args)) { $fragment = vars::apply_assoc($fragment, $cache_args); } $nested = $document->fragment($fragment); } break; case 'www:xquery': require_once www_root . 'thirdparty/xquerylite/class_xquery_lite.php'; $xq = new XqueryLite(); $fragment = $xq->evaluate_xqueryl(fs::checked_read($node['@src'])); $nested = $document->fragment($fragment); break; case 'www:style': $src = $node['@src']; $nested = $document->element('link'); $nested['@rel'] = 'stylesheet'; $nested['@href'] = $src . '?' . fs::crc32($src); break; case 'www:script': $src = $node['@src']; $nested = $document->element('script', ''); $nested['@type'] = 'text/javascript'; $nested['@src'] = $src . '?' . fs::crc32($src); break; case 'www:img': $src = $node['@src']; $nested = $document->element('img'); $nested['@src'] = $src . '?' . crc32(fs::modification($src)); foreach ($node->attributes() as $name => $value) { if ($name != 'src') { $nested['@' . $name] = $value; } } break; case 'www:bbcode': $allow = $node->attribute('allow'); $deny = $node->attribute('deny'); $nested = bbcode::parse($node, $allow ? preg_split('/, */', $allow) : null, $deny ? preg_split('/, */', $deny) : null); break; default: runtime_error('Unknown extension element: ' . $node->name()); } self::replace_node($document, $node, $nested); } }
function request($params, $global, $get, $post, $cookies, $files, $extensions) { $values = []; $batch = []; foreach (array_merge($global, $this->params) as $name => $param) { $value = self::substitute($param->value, $params); switch ($param->type) { case 'value': $values[$name] = $value; break; case 'json': $values[$name] = json::decode(fs::checked_read($value)); break; case 'xml': $values[$name] = 'TODO: Add XML support here'; break; case 'query': $batch[$name] = $value; break; case 'get': isset($get[$value]) or isset($param->default) or runtime_error('GET parameter not found: ' . $name); $values[$name] = isset($get[$value]) ? $get[$value] : $param->default; break; case 'post': isset($post[$value]) or isset($param->default) or runtime_error('POST parameter not found: ' . $name); $values[$name] = isset($post[$value]) ? $post[$value] : $param->default; break; case 'cookie': isset($cookies[$value]) or isset($param->default) or runtime_error('Cookie parameter not found: ' . $name); $values[$name] = isset($cookies[$value]) ? $cookies[$value] : $param->default; break; } } foreach ($batch as $name => &$value) { $value = preg_replace_callback('/\\{@(\\w+)\\}/', function ($matches) use($values) { return isset($values[$matches[1]]) ? $values[$matches[1]] : $matches[0]; }, $value); } $response = []; $params = array_merge($values, empty($batch) ? [] : $this->api->batch($batch)); if ($this->script) { $script_args = $params; if ($this->files) { $script_args = array_merge($script_args, [$this->files => $files]); } $prototype = '$' . implode(',$', array_keys($script_args)); $script = ''; foreach ($this->require as $require) { $script .= 'require_once(\'' . $this->scripts . $require . '\');'; } $script .= 'return function(' . (empty($script_args) ? '' : $prototype) . ") { {$this->script} };"; $closure = eval($script); if ($result = call_user_func_array($closure->bindTo($this->api), array_values($script_args))) { $params = array_replace($params, $result); } foreach (['cookies', 'redirect', 'headers'] as $builtin) { $mangled = '_' . $builtin; if (isset($params[$mangled])) { $response[$builtin] = $params[$mangled]; unset($params[$mangled]); } } } if ($this->template) { switch ($this->engine) { case 'twig': $loader = new Twig_Loader_Filesystem($this->templates); $options = []; if ($this->cache) { $options['cache'] = $this->cache; } $twig = new Twig_Environment($loader, $options); //$twig->addExtension(new Twig_Extension_Debug()); $twig->getExtension('core')->setNumberFormat(0, '.', ' '); $closure = function ($haystack, $needle) { return $needle === "" or strpos($haystack, $needle) === 0; }; $function = new Twig_SimpleFunction('starts_with', $closure); $twig->addFunction($function); $closure = function ($filename) { return json_decode(file_get_contents($this->data . $filename)); }; $function = new Twig_SimpleFunction('json', $closure->bindTo($this, $this)); $twig->addFunction($function); $closure = function ($object) { $array = []; foreach ($object as $key => $value) { $array[$key] = $value; } return $array; }; $filter = new Twig_SimpleFilter('array', $closure); $twig->addFilter($filter); $closure = function ($number) { return ceil($number); }; $filter = new Twig_SimpleFilter('ceil', $closure); $twig->addFilter($filter); $closure = function ($string) { return md5($string); }; $filter = new Twig_SimpleFilter('md5', $closure); $twig->addFilter($filter); $closure = function ($alias) { return $this->locale->get($alias); }; $function = new Twig_SimpleFilter('local', $closure->bindTo($this, $this)); $twig->addFilter($function); if (!is_null($extensions) and isset($extensions['twig'])) { if (isset($extensions['twig']['filters'])) { foreach ($extensions['twig']['filters'] as $name => $closure) { $twig->addFilter(new Twig_SimpleFilter($name, $closure->bindTo($this, $this))); } } if (isset($extensions['twig']['functions'])) { foreach ($extensions['twig']['functions'] as $name => $closure) { $twig->addFunction(new Twig_SimpleFunction($name, $closure->bindTo($this, $this))); } } } $template = $twig->loadTemplate($this->template); $response['content'] = $template->render($params); break; case 'smarty': $smarty = new Smarty(); $smarty->setTemplateDir($this->templates); if ($this->cache) { $smarty->setCompileDir($this->cache)->setCacheDir($this->cache); } $smarty->assign($params); $response['content'] = @$smarty->fetch($this->template); break; } } return (object) $response; }