diff --git a/library/Icinga/File/Json.php b/library/Icinga/File/Json.php new file mode 100644 index 000000000..f45f0f1a4 --- /dev/null +++ b/library/Icinga/File/Json.php @@ -0,0 +1,129 @@ +query = $query; + } + + /** + * Factory + * + * @param Traversable $query The query to generate JSON from the result of + * + * @return static + */ + public static function create(Traversable $query) + { + return new static($query); + } + + /** + * Render JSON and pass it to the user agent (as with {@link fpassthru()}) + */ + public function dump() + { + $this->render()->fpassthru(); + } + + /** + * Return the rendered JSON + * + * @return string + */ + public function __toString() + { + return (string) $this->render(); + } + + /** + * Return the rendered JSON + * + * @return Buffer + */ + protected function render() + { + if ($this->renderBuffer === null) { + $this->renderBuffer = new Buffer(); + $this->renderBuffer->append('['); + + $first = true; + foreach ($this->query as $row) { + if ($first) { + $first = false; + } else { + $this->renderBuffer->append(','); + } + $this->renderBuffer->append($this->renderRow($row)); + } + + $this->renderBuffer->append(']'); + } + + return $this->renderBuffer; + } + + /** + * Return a JSON string representing the given columns of a single row + * + * @param stdClass $columns + * + * @return string + * + * @throws IcingaException In case of an error + */ + protected function renderRow(stdClass $columns) + { + $result = json_encode($columns); + if ($result === false) { + if (function_exists('json_last_error_msg')) { + // since PHP 5.5 + $errorMessage = json_last_error_msg(); + } else { + $lastError = json_last_error(); + $constants = get_defined_constants(true); + $errorMessage = 'Unknown error'; + foreach ($constants['json'] as $constant => $value) { + if ($value === $lastError && substr($constant, 0, 11) === 'JSON_ERROR_') { + $errorMessage = $constant; + break; + } + } + } + + throw new IcingaException('Couldn\'t encode %s as JSON: %s', print_r($columns, true), $errorMessage); + } + return $result; + } +} diff --git a/modules/monitoring/library/Monitoring/Controller.php b/modules/monitoring/library/Monitoring/Controller.php index 9424110fa..122b15d97 100644 --- a/modules/monitoring/library/Monitoring/Controller.php +++ b/modules/monitoring/library/Monitoring/Controller.php @@ -8,7 +8,7 @@ use Icinga\Exception\QueryException; use Icinga\Data\Filter\Filter; use Icinga\Data\Filterable; use Icinga\File\Csv; -use Icinga\Util\Json; +use Icinga\File\Json; use Icinga\Web\Controller as IcingaWebController; use Icinga\Web\Url; @@ -60,8 +60,13 @@ class Controller extends IcingaWebController 'Content-Disposition', 'inline; filename=' . $this->getRequest()->getActionName() . '.json' ) - ->appendBody(Json::encode($query->fetchAll())) - ->sendResponse(); + ->sendHeaders(); + + while (ob_get_level()) { + ob_end_clean(); + } + Json::create($query)->dump(); + exit; case 'csv': $response = $this->getResponse();