doesn't work '/\f/', ]; $replace = [ '\\\\\\', '\\"', '\\$', '\\t', '\\r', '\\n', // '\\b', '\\f', ]; $string = preg_replace($special, $replace, $string); return '"' . $string . '"'; } public static function renderPhpValue($value) { if (is_null($value)) { return static::renderNull(); } if (is_bool($value)) { return static::renderBoolean($value); } if (is_int($value)) { return static::renderInteger($value); } if (is_float($value)) { return static::renderFloat($value); } // TODO: // if (is_object($value) || static::isAssocArray($value)) { // return static::renderHash($value, $prefix) // TODO: also check array if (is_array($value)) { return static::renderArray($value); } if (is_string($value)) { return static::renderString($value); } throw new InvalidArgumentException(sprintf( 'Unexpected type %s', var_export($value, 1) )); } public static function renderDictionaryKey($key) { if (preg_match('/^[a-z_]+[a-z0-9_]*$/i', $key)) { return static::escapeIfReserved($key); } return static::renderString($key); } // Requires an array public static function renderArray($array) { $data = []; foreach ($array as $entry) { if ($entry instanceof IcingaConfigRenderer) { $data[] = $entry; } else { $data[] = self::renderString($entry); } } return static::renderEscapedArray($data); } public static function renderEscapedArray($array) { $str = '[ ' . implode(', ', $array) . ' ]'; if (strlen($str) < 60) { return $str; } // Prefix for toConfigString? return "[\n " . implode(",\n ", $array) . "\n]"; } public static function renderDictionary($dictionary) { $values = []; foreach ($dictionary as $key => $value) { $values[$key] = rtrim( self::renderKeyValue( self::renderDictionaryKey($key), $value ) ); } if (empty($values)) { return '{}'; } ksort($values, SORT_STRING); // Prefix for toConfigString? return "{\n" . implode("\n", $values) . "\n}"; } public static function renderExpression($string) { return "{{\n " . $string . "\n}}"; } public static function alreadyRendered($string) { return new IcingaConfigRendered($string); } public static function isReserved($string) { return in_array($string, self::$reservedWords, true); } public static function escapeIfReserved($string) { if (self::isReserved($string)) { return '@' . $string; } return $string; } public static function isValidInterval($interval) { if (ctype_digit($interval)) { return true; } $parts = preg_split('/\s+/', $interval, -1, PREG_SPLIT_NO_EMPTY); foreach ($parts as $part) { if (! preg_match('/^(\d+)([dhms]?)$/', $part)) { return false; } } return true; } public static function parseInterval($interval) { if ($interval === null || $interval === '') { return null; } if (is_int($interval) || ctype_digit($interval)) { return (int) $interval; } $parts = preg_split('/\s+/', $interval, -1, PREG_SPLIT_NO_EMPTY); $value = 0; foreach ($parts as $part) { if (! preg_match('/^(\d+)([dhms]?)$/', $part, $m)) { throw new InvalidArgumentException(sprintf( '"%s" is not a valid time (duration) definition', $interval )); } switch ($m[2]) { case 'd': $value += $m[1] * 86400; break; case 'h': $value += $m[1] * 3600; break; case 'm': $value += $m[1] * 60; break; default: $value += (int) $m[1]; } } return $value; } public static function renderInterval($interval) { // TODO: compat only, do this at munge time. All db fields should be int $seconds = self::parseInterval($interval); if ($seconds === 0) { return '0s'; } $steps = [ 'd' => 86400, 'h' => 3600, 'm' => 60, ]; foreach ($steps as $unit => $duration) { if ($seconds % $duration === 0) { return (int) floor($seconds / $duration) . $unit; } } return $seconds . 's'; } public static function stringHasMacro($string, $macroName = null) { $len = strlen($string); $start = false; // TODO: robust UTF8 support. It works, but it is not 100% correct for ($i = 0; $i < $len; $i++) { if ($string[$i] === '$') { if ($start === false) { $start = $i; } else { // Escaping, $$ if ($start + 1 === $i) { $start = false; } else { if ($macroName === null) { return true; } if ($macroName === substr($string, $start + 1, $i - $start - 1)) { return true; } $start = false; } } } } return false; } /** * Hint: this isn't complete, but let's restrict ourselves right now * * @param $name * @return bool */ public static function isValidMacroName($name) { return preg_match('/^[A-z_][A-z_.\d]+$/', $name) && ! preg_match('/\.$/', $name); } public static function renderStringWithVariables($string, array $whiteList = null) { $len = strlen($string); $start = false; $parts = []; // TODO: UTF8... $offset = 0; for ($i = 0; $i < $len; $i++) { if ($string[$i] === '$') { if ($start === false) { $start = $i; } else { // Ignore $$ if ($start + 1 === $i) { $start = false; } else { // We got a macro $macroName = substr($string, $start + 1, $i - $start - 1); if (static::isValidMacroName($macroName)) { if ($whiteList === null || in_array($macroName, $whiteList)) { if ($start > $offset) { $parts[] = static::renderString( substr($string, $offset, $start - $offset) ); } $parts[] = $macroName; $offset = $i + 1; } } $start = false; } } } } if ($offset < $i) { $parts[] = static::renderString(substr($string, $offset, $i - $offset)); } if (! empty($parts)) { return implode(' + ', $parts); } return '""'; } }