/** * 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; }
/** * Read the ini file contained in a string and return a mutable DOM that can be used * to change the content of an INI file. * * @param $str A string containing the whole ini file * * @return Document The mutable DOM object. * @throws ConfigurationError In case the file is not parseable */ public static function parseIni($str) { $doc = new Document(); $sec = null; $dir = null; $coms = array(); $state = self::LINE_START; $escaping = null; $token = ''; $line = 0; for ($i = 0; $i < strlen($str); $i++) { $s = $str[$i]; switch ($state) { case self::LINE_START: if (ctype_space($s)) { continue; } switch ($s) { case '[': $state = self::SECTION; break; case ';': $state = self::COMMENT; break; default: $state = self::DIRECTIVE_KEY; $token = $s; break; } break; case self::ESCAPE: $token .= $s; $state = $escaping; $escaping = null; break; case self::SECTION: if ($s === "\n") { self::throwParseError('Unterminated SECTION', $line); } elseif ($s === '\\') { $state = self::ESCAPE; $escaping = self::SECTION; } elseif ($s !== ']') { $token .= $s; } else { $sec = new Section($token); $sec->setCommentsPre($coms); $doc->addSection($sec); $dir = null; $coms = array(); $state = self::LINE_END; $token = ''; } break; case self::DIRECTIVE_KEY: if ($s !== '=') { $token .= $s; } else { $dir = new Directive($token); $dir->setCommentsPre($coms); if (isset($sec)) { $sec->addDirective($dir); } else { Logger::warning(sprintf('Ini parser warning: section-less directive "%s" ignored. (l. %d)', $token, $line)); } $coms = array(); $state = self::DIRECTIVE_VALUE_START; $token = ''; } break; case self::DIRECTIVE_VALUE_START: if (ctype_space($s)) { continue; } elseif ($s === '"') { $state = self::DIRECTIVE_VALUE_QUOTED; } else { $state = self::DIRECTIVE_VALUE; $token = $s; } break; case self::DIRECTIVE_VALUE: /* Escaping non-quoted values is not supported by php_parse_ini, it might be reasonable to include in case we are switching completely our own parser implementation */ if ($s === "\n" || $s === ";") { $dir->setValue($token); $token = ''; if ($s === "\n") { $state = self::LINE_START; $line++; } elseif ($s === ';') { $state = self::COMMENT; } } else { $token .= $s; } break; case self::DIRECTIVE_VALUE_QUOTED: if ($s === '\\') { $state = self::ESCAPE; $escaping = self::DIRECTIVE_VALUE_QUOTED; } elseif ($s !== '"') { $token .= $s; } else { $dir->setValue($token); $token = ''; $state = self::LINE_END; } break; case self::COMMENT: case self::COMMENT_END: if ($s !== "\n") { $token .= $s; } else { $com = new Comment(); $com->setContent($token); $token = ''; // Comments at the line end belong to the current line's directive or section. Comments // on empty lines belong to the next directive that shows up. if ($state === self::COMMENT_END) { if (isset($dir)) { $dir->setCommentPost($com); } else { $sec->setCommentPost($com); } } else { $coms[] = $com; } $state = self::LINE_START; $line++; } break; case self::LINE_END: if ($s === "\n") { $state = self::LINE_START; $line++; } elseif ($s === ';') { $state = self::COMMENT_END; } break; } } // process the last token switch ($state) { case self::COMMENT: case self::COMMENT_END: $com = new Comment(); $com->setContent($token); if ($state === self::COMMENT_END) { if (isset($dir)) { $dir->setCommentPost($com); } else { $sec->setCommentPost($com); } } else { $coms[] = $com; } break; case self::DIRECTIVE_VALUE: $dir->setValue($token); $sec->addDirective($dir); break; case self::ESCAPE: case self::DIRECTIVE_VALUE_QUOTED: case self::DIRECTIVE_KEY: case self::SECTION: self::throwParseError('File ended in unterminated state ' . $state, $line); } if (!empty($coms)) { $doc->setCommentsDangling($coms); } return $doc; }