diff options
Diffstat (limited to 'library/Icinga/File/Ini/Dom')
-rw-r--r-- | library/Icinga/File/Ini/Dom/Comment.php | 37 | ||||
-rw-r--r-- | library/Icinga/File/Ini/Dom/Directive.php | 166 | ||||
-rw-r--r-- | library/Icinga/File/Ini/Dom/Document.php | 132 | ||||
-rw-r--r-- | library/Icinga/File/Ini/Dom/Section.php | 190 |
4 files changed, 525 insertions, 0 deletions
diff --git a/library/Icinga/File/Ini/Dom/Comment.php b/library/Icinga/File/Ini/Dom/Comment.php new file mode 100644 index 0000000..c202d0f --- /dev/null +++ b/library/Icinga/File/Ini/Dom/Comment.php @@ -0,0 +1,37 @@ +<?php +/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ + +namespace Icinga\File\Ini\Dom; + +/** + * A single comment-line in an INI file + */ +class Comment +{ + /** + * The comment text + * + * @var string + */ + protected $content; + + /** + * Set the text content of this comment + * + * @param $content + */ + public function setContent($content) + { + $this->content = $content; + } + + /** + * Render this comment into INI markup + * + * @return string + */ + public function render() + { + return ';' . $this->content; + } +} diff --git a/library/Icinga/File/Ini/Dom/Directive.php b/library/Icinga/File/Ini/Dom/Directive.php new file mode 100644 index 0000000..4279a5f --- /dev/null +++ b/library/Icinga/File/Ini/Dom/Directive.php @@ -0,0 +1,166 @@ +<?php +/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ + +namespace Icinga\File\Ini\Dom; + +use Icinga\Exception\ConfigurationError; + +/** + * A key value pair in a Section + */ +class Directive +{ + /** + * The value of this configuration directive + * + * @var string + */ + protected $key; + + /** + * The immutable name of this configuration directive + * + * @var string + */ + protected $value; + + /** + * Comments added one line before this directive + * + * @var Comment[] The comment lines + */ + protected $commentsPre = null; + + /** + * Comment added at the end of the same line + * + * @var Comment + */ + protected $commentPost = null; + + /** + * @param string $key The name of this configuration directive + * + * @throws ConfigurationError + */ + public function __construct($key) + { + $this->key = trim($key); + if (strlen($this->key) < 1) { + throw new ConfigurationError(sprintf('Ini error: empty directive key.')); + } + } + + /** + * Return the name of this directive + * + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * Return the value of this configuration directive + * + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * Set the value of this configuration directive + * + * @param string $value + */ + public function setValue($value) + { + $this->value = trim($value); + } + + /** + * Set the comments to be rendered on the line before this directive + * + * @param Comment[] $comments + */ + public function setCommentsPre(array $comments) + { + $this->commentsPre = $comments; + } + + /** + * Return the comments to be rendered on the line before this directive + * + * @return Comment[] + */ + public function getCommentsPre() + { + return $this->commentsPre; + } + + /** + * Set the comment rendered on the same line of this directive + * + * @param Comment $comment + */ + public function setCommentPost(Comment $comment) + { + $this->commentPost = $comment; + } + + /** + * Render this configuration directive into INI markup + * + * @return string + */ + public function render() + { + $str = ''; + if (! empty($this->commentsPre)) { + $comments = array(); + foreach ($this->commentsPre as $comment) { + $comments[] = $comment->render(); + } + $str = implode(PHP_EOL, $comments) . PHP_EOL; + } + $str .= sprintf('%s = "%s"', $this->sanitizeKey($this->key), $this->sanitizeValue($this->value)); + if (isset($this->commentPost)) { + $str .= ' ' . $this->commentPost->render(); + } + return $str; + } + + /** + * Assure that the given identifier contains no newlines and pending or trailing whitespaces + * + * @param $str The string to sanitize + * + * @return string + */ + protected function sanitizeKey($str) + { + return trim(str_replace(PHP_EOL, ' ', $str)); + } + + /** + * Escape the significant characters in directive values, normalize line breaks and assure that + * the character contains no linebreaks + * + * @param $str The string to sanitize + * + * @return mixed|string + */ + protected function sanitizeValue($str) + { + $str = trim($str); + $str = str_replace('\\', '\\\\', $str); + $str = str_replace('"', '\"', $str); + $str = str_replace("\r", '\r', $str); + $str = str_replace("\n", '\n', $str); + + return $str; + } +} diff --git a/library/Icinga/File/Ini/Dom/Document.php b/library/Icinga/File/Ini/Dom/Document.php new file mode 100644 index 0000000..f38f33e --- /dev/null +++ b/library/Icinga/File/Ini/Dom/Document.php @@ -0,0 +1,132 @@ +<?php +/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ + +namespace Icinga\File\Ini\Dom; + +class Document +{ + /** + * The sections of this INI file + * + * @var Section[] + */ + protected $sections = array(); + + /** + * The comemnts at file end that belong to no particular section + * + * @var Comment[] + */ + protected $commentsDangling; + + /** + * Append a section to the end of this INI file + * + * @param Section $section + */ + public function addSection(Section $section) + { + $this->sections[$section->getName()] = $section; + } + + /** + * Return whether this INI file has the section with the given key + * + * @param string $name + * + * @return bool + */ + public function hasSection($name) + { + return isset($this->sections[trim($name)]); + } + + /** + * Return the section with the given name + * + * @param string $name + * + * @return Section + */ + public function getSection($name) + { + return $this->sections[trim($name)]; + } + + /** + * Set the section with the given name + * + * @param string $name + * @param Section $section + * + * @return Section + */ + public function setSection($name, Section $section) + { + return $this->sections[trim($name)] = $section; + } + + /** + * Remove the section with the given name + * + * @param string $name + */ + public function removeSection($name) + { + unset($this->sections[trim($name)]); + } + + /** + * Set the dangling comments at file end that belong to no particular directive + * + * @param Comment[] $comments + */ + public function setCommentsDangling(array $comments) + { + $this->commentsDangling = $comments; + } + + /** + * Get the dangling comments at file end that belong to no particular directive + * + * @return array + */ + public function getCommentsDangling() + { + return $this->commentsDangling; + } + + /** + * Render this document into the corresponding INI markup + * + * @return string + */ + public function render() + { + $sections = array(); + foreach ($this->sections as $section) { + $sections []= $section->render(); + } + $str = implode(PHP_EOL, $sections); + if (! empty($this->commentsDangling)) { + foreach ($this->commentsDangling as $comment) { + $str .= PHP_EOL . $comment->render(); + } + } + return $str; + } + + /** + * Convert $this to an array + * + * @return array + */ + public function toArray() + { + $a = array(); + foreach ($this->sections as $section) { + $a[$section->getName()] = $section->toArray(); + } + return $a; + } +} diff --git a/library/Icinga/File/Ini/Dom/Section.php b/library/Icinga/File/Ini/Dom/Section.php new file mode 100644 index 0000000..f877c87 --- /dev/null +++ b/library/Icinga/File/Ini/Dom/Section.php @@ -0,0 +1,190 @@ +<?php +/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ + +namespace Icinga\File\Ini\Dom; + +use Icinga\Exception\ConfigurationError; + +/** + * A section in an INI file + */ +class Section +{ + /** + * The immutable name of this section + * + * @var string + */ + protected $name; + + /** + * All configuration directives of this section + * + * @var Directive[] + */ + protected $directives = array(); + + /** + * Comments added one line before this section + * + * @var Comment[] + */ + protected $commentsPre; + + /** + * Comment added at the end of the same line + * + * @var string + */ + protected $commentPost; + + /** + * @param string $name The immutable name of this section + * + * @throws ConfigurationError When the section name is empty or contains brackets + */ + public function __construct($name) + { + $this->name = trim($name); + if (strlen($this->name) < 1) { + throw new ConfigurationError('Ini file error: empty section identifier'); + } elseif (strpos($name, '[') !== false || strpos($name, ']') !== false) { + throw new ConfigurationError( + 'Ini file error: Section name "%s" must not contain any brackets ([, ])', + $name + ); + } + } + + /** + * Append a directive to the end of this section + * + * @param Directive $directive The directive to append + */ + public function addDirective(Directive $directive) + { + $this->directives[$directive->getKey()] = $directive; + } + + /** + * Remove the directive with the given name + * + * @param string $key They name of the directive to remove + */ + public function removeDirective($key) + { + unset($this->directives[$key]); + } + + /** + * Return whether this section has a directive with the given key + * + * @param string $key The name of the directive + * + * @return bool + */ + public function hasDirective($key) + { + return isset($this->directives[$key]); + } + + /** + * Get the directive with the given key + * + * @param $key string + * + * @return Directive + */ + public function getDirective($key) + { + return $this->directives[$key]; + } + + /** + * Return the name of this section + * + * @return string The name + */ + public function getName() + { + return $this->name; + } + + /** + * Set the comments to be rendered on the line before this section + * + * @param Comment[] $comments + */ + public function setCommentsPre(array $comments) + { + $this->commentsPre = $comments; + } + + /** + * Set the comment rendered on the same line of this section + * + * @param Comment $comment + */ + public function setCommentPost(Comment $comment) + { + $this->commentPost = $comment; + } + + /** + * Render this section into INI markup + * + * @return string + */ + public function render() + { + $dirs = ''; + $i = 0; + foreach ($this->directives as $directive) { + $comments = $directive->getCommentsPre(); + $dirs .= (($i++ > 0 && ! empty($comments)) ? PHP_EOL : '') + . $directive->render() . PHP_EOL; + } + $cms = ''; + if (! empty($this->commentsPre)) { + foreach ($this->commentsPre as $comment) { + $comments[] = $comment->render(); + } + $cms = implode(PHP_EOL, $comments) . PHP_EOL; + } + $post = ''; + if (isset($this->commentPost)) { + $post = ' ' . $this->commentPost->render(); + } + return $cms . sprintf('[%s]', $this->sanitize($this->name)) . $post . PHP_EOL . $dirs; + } + + /** + * Escape the significant characters in sections and normalize line breaks + * + * @param $str The string to sanitize + * + * @return mixed + */ + protected function sanitize($str) + { + $str = trim($str); + $str = str_replace('\\', '\\\\', $str); + $str = str_replace('"', '\\"', $str); + $str = str_replace(';', '\\;', $str); + return str_replace(PHP_EOL, ' ', $str); + } + + /** + * Convert $this to an array + * + * @return array + */ + public function toArray() + { + $a = array(); + foreach ($this->directives as $directive) { + $a[$directive->getKey()] = $directive->getValue(); + } + return $a; + } +} |