2013-06-27 10:14:41 +02:00
|
|
|
<?php
|
2016-02-08 15:41:00 +01:00
|
|
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
2013-06-27 10:14:41 +02:00
|
|
|
|
2016-12-06 15:04:26 +01:00
|
|
|
use Icinga\Web\Dom\DomNodeIterator;
|
2018-01-19 15:40:28 +01:00
|
|
|
use Icinga\Module\Monitoring\Web\Helper\PluginOutputPurifier;
|
2016-12-06 15:04:26 +01:00
|
|
|
|
2016-05-20 12:48:50 +02:00
|
|
|
/**
|
|
|
|
* Plugin output renderer
|
|
|
|
*/
|
2013-06-27 10:14:41 +02:00
|
|
|
class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
|
|
|
|
{
|
2016-05-20 12:48:50 +02:00
|
|
|
/**
|
|
|
|
* The return value of getPurifier()
|
|
|
|
*
|
|
|
|
* @var HTMLPurifier
|
|
|
|
*/
|
2013-06-27 10:14:41 +02:00
|
|
|
protected static $purifier;
|
2013-09-04 18:27:16 +02:00
|
|
|
|
2016-05-20 12:48:50 +02:00
|
|
|
/**
|
|
|
|
* Patterns to be replaced in plain text plugin output
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
2015-02-09 15:38:43 +01:00
|
|
|
protected static $txtPatterns = array(
|
|
|
|
'~\\\n~',
|
|
|
|
'~\\\t~',
|
|
|
|
'~\\\n\\\n~',
|
|
|
|
'~(\[|\()OK(\]|\))~',
|
|
|
|
'~(\[|\()WARNING(\]|\))~',
|
|
|
|
'~(\[|\()CRITICAL(\]|\))~',
|
|
|
|
'~(\[|\()UNKNOWN(\]|\))~',
|
2017-11-09 14:14:09 +01:00
|
|
|
'~(\[|\()UP(\]|\))~',
|
|
|
|
'~(\[|\()DOWN(\]|\))~',
|
2015-02-09 15:38:43 +01:00
|
|
|
'~\@{6,}~'
|
|
|
|
);
|
|
|
|
|
2016-05-20 12:48:50 +02:00
|
|
|
/**
|
|
|
|
* Replacements for $txtPatterns
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
2015-02-09 15:38:43 +01:00
|
|
|
protected static $txtReplacements = array(
|
|
|
|
"\n",
|
|
|
|
"\t",
|
|
|
|
"\n",
|
2015-12-21 12:25:24 +01:00
|
|
|
'<span class="state-ok">$1OK$2</span>',
|
|
|
|
'<span class="state-warning">$1WARNING$2</span>',
|
|
|
|
'<span class="state-critical">$1CRITICAL$2</span>',
|
|
|
|
'<span class="state-unknown">$1UNKNOWN$2</span>',
|
2017-11-09 14:14:09 +01:00
|
|
|
'<span class="state-up">$1UP$2</span>',
|
|
|
|
'<span class="state-down">$1DOWN$2</span>',
|
2015-02-09 15:38:43 +01:00
|
|
|
'@@@@@@',
|
|
|
|
);
|
|
|
|
|
2018-01-16 15:37:30 +01:00
|
|
|
/**
|
|
|
|
* Patterns to be replaced in html plugin output
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected static $htmlPatterns = array(
|
|
|
|
'~\\\n~',
|
|
|
|
'~\\\t~',
|
|
|
|
'~\\\n\\\n~',
|
|
|
|
'~<table~'
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replacements for $htmlPatterns
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected static $htmlReplacements = array(
|
|
|
|
"\n",
|
|
|
|
"\t",
|
|
|
|
"\n",
|
|
|
|
'<table style="font-size: 0.75em"'
|
|
|
|
);
|
|
|
|
|
2016-05-20 12:48:50 +02:00
|
|
|
/**
|
|
|
|
* Render plugin output
|
|
|
|
*
|
|
|
|
* @param string $output
|
|
|
|
* @param bool $raw
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2015-07-07 10:16:12 +02:00
|
|
|
public function pluginOutput($output, $raw = false)
|
2013-06-27 10:14:41 +02:00
|
|
|
{
|
2014-03-04 13:54:23 +01:00
|
|
|
if (empty($output)) {
|
|
|
|
return '';
|
|
|
|
}
|
2015-07-08 15:16:32 +02:00
|
|
|
$output = preg_replace('~<br[^>]*>~', "\n", $output);
|
2016-02-17 11:48:34 +01:00
|
|
|
if (preg_match('~<[^>]*["/\'][^>]*>~', $output)) {
|
2013-06-27 10:14:41 +02:00
|
|
|
// HTML
|
2015-07-06 15:47:04 +02:00
|
|
|
$output = preg_replace(
|
2018-01-16 15:37:30 +01:00
|
|
|
self::$htmlPatterns,
|
|
|
|
self::$htmlReplacements,
|
2018-01-19 15:40:28 +01:00
|
|
|
PluginOutputPurifier::process($output)
|
2013-06-27 10:14:41 +02:00
|
|
|
);
|
2015-11-06 01:56:17 +01:00
|
|
|
$isHtml = true;
|
2013-06-27 10:14:41 +02:00
|
|
|
} else {
|
2015-02-09 15:38:43 +01:00
|
|
|
// Plaintext
|
2015-07-06 15:36:43 +02:00
|
|
|
$output = preg_replace(
|
2015-02-09 15:38:43 +01:00
|
|
|
self::$txtPatterns,
|
|
|
|
self::$txtReplacements,
|
2016-11-23 11:05:39 +01:00
|
|
|
$this->view->escape($output)
|
2015-07-06 15:36:43 +02:00
|
|
|
);
|
2015-11-06 01:56:17 +01:00
|
|
|
$isHtml = false;
|
2015-07-06 15:36:43 +02:00
|
|
|
}
|
2016-02-27 18:00:50 +01:00
|
|
|
$output = trim($output);
|
2016-11-23 11:05:39 +01:00
|
|
|
// Add space after comma where missing, to help browsers to break words in plugin output
|
2016-05-19 11:37:12 +02:00
|
|
|
$output = preg_replace('/,(?=[^\s])/', ', ', $output);
|
2015-07-07 10:16:12 +02:00
|
|
|
if (! $raw) {
|
2015-11-06 01:56:17 +01:00
|
|
|
if ($isHtml) {
|
2016-12-06 15:04:26 +01:00
|
|
|
$output = $this->processHtml($output);
|
2015-12-21 12:25:24 +01:00
|
|
|
$output = '<div class="plugin-output">' . $output . '</div>';
|
2015-11-06 01:56:17 +01:00
|
|
|
} else {
|
2015-12-21 12:25:24 +01:00
|
|
|
$output = '<div class="plugin-output preformatted">' . $output . '</div>';
|
2015-11-06 01:56:17 +01:00
|
|
|
}
|
2015-07-07 10:16:12 +02:00
|
|
|
}
|
|
|
|
return $output;
|
2013-06-27 10:14:41 +02:00
|
|
|
}
|
|
|
|
|
2016-05-20 12:48:50 +02:00
|
|
|
/**
|
2016-12-06 15:04:26 +01:00
|
|
|
* Replace classic Icinga CGI links with Icinga Web 2 links and color state information, if any
|
2016-05-20 12:48:50 +02:00
|
|
|
*
|
|
|
|
* @param string $html
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-12-06 15:04:26 +01:00
|
|
|
protected function processHtml($html)
|
2013-06-27 10:14:41 +02:00
|
|
|
{
|
2017-11-09 14:14:09 +01:00
|
|
|
$pattern = '/[([](OK|WARNING|CRITICAL|UNKNOWN|UP|DOWN)[)\]]/';
|
2016-12-06 15:04:26 +01:00
|
|
|
$doc = new DOMDocument();
|
|
|
|
$doc->loadXML('<div>' . $html . '</div>', LIBXML_NOERROR | LIBXML_NOWARNING);
|
|
|
|
$dom = new RecursiveIteratorIterator(new DomNodeIterator($doc), RecursiveIteratorIterator::SELF_FIRST);
|
|
|
|
$nodesToRemove = array();
|
|
|
|
foreach ($dom as $node) {
|
|
|
|
/** @var \DOMNode $node */
|
|
|
|
if ($node->nodeType === XML_TEXT_NODE) {
|
|
|
|
$start = 0;
|
|
|
|
while (preg_match($pattern, $node->nodeValue, $match, PREG_OFFSET_CAPTURE, $start)) {
|
|
|
|
$offsetLeft = $match[0][1];
|
|
|
|
$matchLength = strlen($match[0][0]);
|
|
|
|
$leftLength = $offsetLeft - $start;
|
2018-03-07 15:55:15 +01:00
|
|
|
// if there is text before the match
|
2016-12-06 15:04:26 +01:00
|
|
|
if ($leftLength) {
|
2018-03-07 15:55:15 +01:00
|
|
|
// create node for leading text
|
2016-12-06 15:04:26 +01:00
|
|
|
$text = new DOMText(substr($node->nodeValue, $start, $leftLength));
|
|
|
|
$node->parentNode->insertBefore($text, $node);
|
|
|
|
}
|
2018-03-07 15:55:15 +01:00
|
|
|
// create the new element for the match
|
2016-12-06 15:04:26 +01:00
|
|
|
$span = $doc->createElement('span', $match[0][0]);
|
|
|
|
$span->setAttribute('class', 'state-' . strtolower($match[1][0]));
|
|
|
|
$node->parentNode->insertBefore($span, $node);
|
2018-03-07 15:55:15 +01:00
|
|
|
|
|
|
|
// start for next match
|
2016-12-06 15:04:26 +01:00
|
|
|
$start = $offsetLeft + $matchLength;
|
|
|
|
}
|
|
|
|
if ($start) {
|
2018-03-07 15:55:15 +01:00
|
|
|
// is there text left?
|
|
|
|
if (strlen($node->nodeValue) > $start) {
|
|
|
|
// create node for trailing text
|
|
|
|
$text = new DOMText(substr($node->nodeValue, $start));
|
|
|
|
$node->parentNode->insertBefore($text, $node);
|
|
|
|
}
|
|
|
|
// delete the old node later
|
2016-12-06 15:04:26 +01:00
|
|
|
$nodesToRemove[] = $node;
|
|
|
|
}
|
|
|
|
} elseif ($node->nodeType === XML_ELEMENT_NODE) {
|
|
|
|
/** @var \DOMElement $node */
|
|
|
|
if ($node->tagName === 'a'
|
|
|
|
&& preg_match('~^/cgi\-bin/status\.cgi\?(.+)$~', $node->getAttribute('href'), $match)
|
|
|
|
) {
|
|
|
|
parse_str($match[1], $params);
|
|
|
|
if (isset($params['host'])) {
|
|
|
|
$node->setAttribute(
|
|
|
|
'href',
|
|
|
|
$this->view->baseUrl('/monitoring/host/show?host=' . urlencode($params['host']))
|
|
|
|
);
|
|
|
|
}
|
2013-06-27 10:14:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-06 15:04:26 +01:00
|
|
|
foreach ($nodesToRemove as $node) {
|
|
|
|
/** @var \DOMNode $node */
|
|
|
|
$node->parentNode->removeChild($node);
|
|
|
|
}
|
2016-05-19 18:38:36 +02:00
|
|
|
|
2016-12-06 15:04:26 +01:00
|
|
|
return substr($doc->saveHTML(), 5, -7);
|
2013-06-27 10:14:41 +02:00
|
|
|
}
|
|
|
|
}
|