funcName = $funcName;
}
/**
* Test for the presence of given XPath function
*
* @param DOMElement $template node
* @param Tag $tag Tag this template belongs to
* @return void
*/
public function check(DOMElement $template, Tag $tag)
{
// Regexp that matches the function call
$regexp = '#(?!<\\pL)' . preg_quote($this->funcName, '#') . '\\s*\\(#iu';
// Allow whitespace around colons (NOTE: colons are unnecessarily escaped by preg_quote())
$regexp = str_replace('\\:', '\\s*:\\s*', $regexp);
foreach ($this->getExpressions($template) as $expr => $node)
{
// Remove string literals from the expression
$expr = preg_replace('#([\'"]).*?\\1#s', '', $expr);
// Test whether the expression contains a document() call
if (preg_match($regexp, $expr))
{
throw new UnsafeTemplateException('An XPath expression uses the ' . $this->funcName . '() function', $node);
}
}
}
/**
* Get all the potential XPath expressions used in given template
*
* @param DOMElement $template node
* @return array XPath expression as key, reference node as value
*/
protected function getExpressions(DOMElement $template)
{
$xpath = new DOMXPath($template->ownerDocument);
$exprs = [];
foreach ($xpath->query('//@*') as $attribute)
{
if ($attribute->parentNode->namespaceURI === self::XMLNS_XSL)
{
// Attribute of an XSL element. May or may not use XPath, but it shouldn't produce
// false-positives
$expr = $attribute->value;
$exprs[$expr] = $attribute;
}
else
{
// Attribute of an HTML (or otherwise) element -- Look for inline expressions
foreach (AVTHelper::parse($attribute->value) as $token)
{
if ($token[0] === 'expression')
{
$exprs[$token[1]] = $attribute;
}
}
}
}
return $exprs;
}
}